//
// Unihan Input Method
//
// Copyright © 2002-2007 Sun Wah Linux Ltd.
//
//
// This library is free software; you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as
// published by the Free Software Foundation; either version 2.1 of the
// License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
// USA
//
// $Id: xaux_ext_status.c 757 2007-05-10 08:19:31Z roger $
//

/*
** $Id: xaux_ext_status.c 757 2007-05-10 08:19:31Z roger $
**
** SWin X Auxilliary Objects
** External module -- IM status panel-applet
*/

#ifdef HAVE_CONFIG_H
#  include <config.h>
#endif /* HAVE_CONFIG_H */

#ifdef DEBUG
#define DEBUG_LOG(...) fprintf(stderr, __VA_ARGS__);
#else
#define DEBUG_LOG(...)
#endif

#define _GNU_SOURCE
#include <langinfo.h>
#include <locale.h>
#include <stdlib.h>
#include <string.h>
#include <libintl.h>
#include <sys/select.h>
#include <gtk/gtk.h>
#include <gdk/gdkx.h>
#include <gconf/gconf-client.h>

#include <X11/X.h>
#include <X11/Xatom.h>
#include <X11/Xproto.h>

#include "xaux_common.h"
#include "xaux_ext_common.h"

#include "unihan_xaux.h"
#include "punc_keyboard.h"
#include "us_keyboard.h"
#include "unihan-gconf.h"
#include "setting.h"
#include "Gconf_cb.h"
#include "global.h"
#include "propagate.h"
#include "unihan_property.h"

#if WTPEN
#include "wtpen_wrapper.h"
#endif

#ifdef WITH_HWPENX
#  include "hwpenx_wrapper.h"
#endif

#if TIMEBOMB
#  include <langinfo.h>
#endif

#define VOID_IM_ID 0xFFFF
#define VOID_IC_ID 0xFFFF

#define _(x) gettext (x)
#define N_(x) (x)

Bool xaux_ext_Start(xaux_class_t *, aux_ext_data_t *, Atom atom);
Bool xaux_ext_Draw(xaux_class_t *, aux_ext_data_t *, Atom atom);
Bool xaux_ext_Done(xaux_class_t *, aux_ext_data_t *, Atom atom);
static GdkFilterReturn xaux_ext_event_handler(GdkXEvent *gdk_xevent, GdkEvent *event, gpointer user_data);

/* the following 4 functions are for enabling and disabling the hiding of the applet */
static gboolean applet_menu_enter_notify_event_handler(GtkWidget *widget,
							GdkEventCrossing *event,
							gpointer user_data);
static gboolean applet_menu_leave_notify_event_handler(GtkWidget *widget,
							GdkEventCrossing *event,
							gpointer user_data);
#if NEW_PROPERTY
#else
static void applet_tcsc_button_pressed_event_handler(GtkButton*, gpointer);
static void applet_tcsc_menu_deactivate_event_handler(GtkMenuShell *menushell, gpointer user_data);
#endif
#if NEW_PROPERTY
//static void hide_im_button();
#endif
#if NEW_PROPERTY
#else
void create_im_menu();
static void popup_im_menu_from_im_button(GtkWidget *, gpointer);
#endif
/* static void destroy_im_menu(GtkWidget*, gpointer); */
void send_to_engine(int, int *, int, char **);
static GtkWidget *create_plug(void);
#if NEW_PROPERTY
#else
static void receive_tcsc_mode(aux_ext_data_t *);
#endif
static void receive_im_list(aux_ext_data_t *);
static void switch_im_handler(GtkMenuItem *, gpointer);
#if NEW_PROPERTY
#else
static void toggle_width_handler(GtkMenuItem *, gpointer);
static void toggle_puncce_handler(GtkMenuItem *, gpointer);
static void tcsc_item_handler(GtkMenuItem *, gpointer);
#endif
static void show_about_box(void);
#if NEW_PROPERTY
static gint icon_im_press_handler(GtkWidget *, GdkEventButton *, gpointer);
#endif
static gint icon_press_handler(GtkWidget *, GdkEventButton *, gpointer);
static gint pref_item_handler(GtkMenuItem *, gpointer);
static gint about_item_handler(GtkMenuItem *, gpointer);
static void plug_embedded_handler(GtkPlug *, gpointer);
static gboolean plug_client_msg_handler(GtkWidget *, GdkEventClient *, gpointer);
static void clipboard_get_handler(GtkClipboard *, GtkSelectionData *, guint, gpointer);
static void set_window_icon(void);
static gboolean is_unicode_charset(gchar *);
#if NEW_PROPERTY
#else
static void tcsc_item_activate(GtkWidget *, gpointer);
#endif
static gboolean commit_string_cleared(GtkWidget *, GdkEventSelection *, gpointer);
static void commit_string_received(GtkWidget *, GtkSelectionData *, guint, gpointer);
static void applet_window_realize(GtkWidget *, gpointer);
static void menu_position_func(GtkMenu *, gint *, gint *, gboolean *, gpointer);
static void punc_kbd_item_handler(GtkCheckMenuItem *, gpointer);
static void us_kbd_item_handler(GtkCheckMenuItem *, gpointer);
static gboolean lost_focus_timeout(gpointer data);
static void find_system_tray(void);
static void dock_plug_to_system_tray(GtkWidget *, Window);
static GdkFilterReturn manager_filter(GdkXEvent *, GdkEvent *, gpointer);
#if NEW_PROPERTY
int controls_retreive_property_node_from_tree (UnihanPropertyList* property_list, PropertyTree* property_tree, PropertyNode** nodes);
PropertyTree* status_model_retreive_property_list(UnihanPropertyList*  property_list);
static gboolean gnode_traverse_fun(PropertyNode *node, gpointer data);
UnihanProperty * convert_string_to_properties(aux_ext_data_t *aux_ext_data);
UnihanPropertyList * convert_string_to_properties_list(aux_ext_data_t *aux_ext_data);
#endif
/* status_control */
static StatusControls *status_controls_new(StatusWindow *w);
static void status_controls_free(StatusControls *c);
#if NEW_PROPERTY
#else
static void controls_puncce_updated(gboolean is_cp);
static void controls_fullwidth_updated(gboolean is_fullwidth);
#endif
static void controls_current_im_updated(IMInfo *im);
#if NEW_PROPERTY
#else
static void controls_tcsc_mode_updated(UnihanTCSCMode tcsc);
#endif
static void controls_unihan_available(gboolean avail);

/* status_model */
static StatusModel *status_model_init(void);
static void status_model_free(StatusModel *m);
static void status_model_im_list_set(StatusModel *m, GList *new_im_list);
static void status_model_im_curr_list_set(StatusModel *m, GList *new_im_list);
static void status_model_current_im_set_by_id(StatusModel *m, gchar *im_id);
#if NEW_PROPERTY
#else
static void status_model_tcsc_mode_set(StatusModel *m, UnihanTCSCMode tcsc);
#endif

/* depricate */
#if NEW_PROPERTY
#else
static void status_fullwidth_set(StatusModel *m, gboolean is_fullwidth);
#endif
static void status_unihan_available_set(StatusModel *m, gboolean avail);
//static void status_punc_mode_set(StatusModel *m, gboolean punc);
#if NEW_PROPERTY
#else
static void status_puncce_set(StatusModel *m, gboolean is_cp);
#endif
//static char *status_get_next_im_by_id(StatusModel *m, char *id);

/* status_window */
static StatusWindow *status_window_new(StatusModel *m);
static void status_window_free(StatusWindow *w);

static void present_applet_window(void);
static void conversion_off_handler(GtkMenuItem *w, gpointer data);
static GtkWidget *create_menu_separator(void);

#ifdef WITH_HWPENX
static void hwpenx_start_failed(void);
static void hwpenx_exited(void);
static void hwpenx_item_handler(GtkCheckMenuItem *, gpointer);
#endif

#if WTPEN
static void wtpen_start_failed(void);
static void wtpen_exited(void);
static void wtpen_item_handler(GtkCheckMenuItem *, gpointer);
#endif
#if NEW_PROPERTY
//static void status_current_im_load_properties(UnihanPropertyList *plist);
static gint check_key_string_tree(char *string);
#endif

#if TIMEBOMB
static void demo_expired(void);
#endif

//For toggle controls floating state dynamically
void on_Status_In_Tray_toggled(GConfClient *, guint, GConfEntry *, gpointer);
//For change tcsc mode dynamiclly from unihan2-pref
void check_module_info(GConfClient *, guint, GConfEntry *, gpointer);
void on_tc_sc_changed(GConfClient *, guint, GConfEntry *, gpointer);
void on_phrase_mode_changed(GConfClient *, guint, GConfEntry *, gpointer);

//For enable the moving of floating_control
static void hack_NET_SUPPORTED(void);
//timeout for moving floating statsbar
static gboolean start_time_out(gpointer data);
static gboolean write_coordinates(gpointer data); 
static gboolean clean_timer_for_moving(gpointer data);

static void link_button_clicked_handler(GtkWidget *widget, gpointer data);

static char *orig_codeset = NULL;

#define ATOM_NUM_MODULES	32
/* Define Aux class */
xaux_class_t xaux_class = {
	AUX_STATUS_CLASS_NAME, 1,
	UNIHAN_XAUX_DIR "/gnome/xaux_ext_status",
	(Window)0, (Window)0, (Window)0,
	(Atom)0, (Atom)0, (Atom)0, (Atom)0,
	{ (Atom)0 }, ATOM_NUM_MODULES, 0,
	{ (Atom)0 }, ATOM_NUM_MODULES, 0,
	NULL,
};
static xaux_class_t *xc_ = NULL;
static int im_ = VOID_IM_ID;
static int ic_ = VOID_IC_ID;
static int xbe_im = VOID_IM_ID;
static int xbe_ic = VOID_IC_ID;

static GtkWidget *plug = NULL;
static GtkClipboard *status_clipboard = NULL;
GtkClipboard *prefedit_clipboard = NULL;
#if NEW_PROPERTY
#else
static gboolean stop_sending_tcsc = FALSE;
#endif
static GtkTooltips *tooltips;
static GdkAtom commit_string_atom;
static gboolean im_menu_ignore_activate = FALSE;

#ifdef WITH_HWPENX
static gboolean hwpenxIgnoreToggle = FALSE;
static GtkWidget *hwpenx_item = NULL;
#endif

#if WTPEN
static gboolean wtpenIgnoreToggle = FALSE;
static GtkWidget *wtpen_item = NULL;
#endif

static GtkWidget *punc_kbd_item = NULL;
static gulong punc_kbd_item_handler_id;
static gboolean puncKbdIgnoreToggle = FALSE;
static GtkWidget *us_kbd_item = NULL;
static gulong us_kbd_item_handler_id;
static gboolean usKbdIgnoreToggle = FALSE;

static gboolean focused = FALSE;
static int focused_im = 0;
static int focused_ic = 0;

static char *locale = NULL;
static guint focus_lost_timer = 0;

#if TIMEBOMB
static gboolean expired = FALSE;
static time_t expire_date = 0;
#endif

StatusModel *model = NULL;
StatusWindow *window = NULL;
int english_im_flag = 0;
int imflag = 0;
char *treestring;
int property_count;
GList *imlist = NULL;
IMInfo *info_list = NULL;

PropertyTree *property_tree;

#define TARGET_PLUG_ID 		1
#define TARGET_CURR_IM_LIST 	2
#define TARGET_ALL_IM_LIST      3
#define TARGET_SYMBOL_LIST      4
#define TARGET_WORD_LIST        5
#define TARGET_CLIENT_WINDOW	6

int click_status = 0;
int unset_focus_before = 0;
struct timeval tv;
gboolean already_plugged = FALSE;
gboolean no_tcsc_conv = TRUE;
guint timer_for_moving = 0;
guint timer_for_clean = 0;

static gboolean beep_on_error = FALSE;

/* ------------------------------------------------------------------------- */
int
main(int argc, char *argv[])
{
	GError *err = NULL;
        GConfClient *client;
	/* 
	** Always use UTF-8 ... otherwise we need to convert everything
	** sent from the LE back from nl_langinfo(CODESET) to UTF-8!
	*/
	locale = strdup(setlocale(LC_ALL, ""));
	orig_codeset = nl_langinfo(CODESET);
	gtk_set_locale();
	
	/* Initialize the i18n stuff */
	bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
	bindtextdomain(GETTEXT_PACKAGE, LOCALEDIR);
	textdomain(GETTEXT_PACKAGE);

	gtk_init(&argc, &argv);
	//gnome_program_init(PACKAGE, VERSION, LIBGNOMEUI_MODULE,
	//		   argc, argv, GNOME_PARAM_NONE);

	if (!gconf_init(argc, argv, &err)) {
		g_error("Failed to init GConf: %s", err->message);
		exit(EXIT_FAILURE);
	}

        /* Initialize the model that represents Unihan's state */
        model = status_model_init();

	tooltips = gtk_tooltips_new();
        window = status_window_new(model);
	set_window_icon();

	/* 
	** this plug is for plugging into various sockets
	** sockets will be created for the GNOME 1.x panel, GNOME 2.0 panel,
	** and probably the KDE panel
	*/
	plug = create_plug();

	/* Register aux class */
	if (xaux_ext_init_classes(GDK_WINDOW_XDISPLAY(window->appletWindow->window), 
				  &xaux_class,
				  GDK_WINDOW_XWINDOW(window->appletWindow->window)) == False){
		//g_error("Unihan - StatusAux: cannot register aux class!");
		return 2;
	}

	/*
	** create clipboards to advertise to the world about:
	** 1) the list of IMs available
	** 2) the Plug's window ID, for use for sockets
        ** 3) the list of symbols available
        ** 4) the list of words available
	*/
	status_clipboard = gtk_clipboard_get(gdk_atom_intern("_UNIHAN_STATUS", FALSE));
	{
		GtkTargetEntry targets[6] = {
			{ "_PLUG_ID", 0, TARGET_PLUG_ID },
			{ "_IM_CURR_LIST", 0, TARGET_CURR_IM_LIST },
                        { "_IM_ALL_LIST", 0, TARGET_ALL_IM_LIST },
                        { "_SYMBOL_LIST", 0, TARGET_SYMBOL_LIST },
                        { "_WORD_LIST", 0, TARGET_WORD_LIST },
			{ "CLIENT_WINDOW", 0, TARGET_CLIENT_WINDOW },
		};
		gtk_clipboard_set_with_data(status_clipboard, targets, 6, 
					    clipboard_get_handler, NULL, NULL);
	}
	prefedit_clipboard = gtk_clipboard_get(gdk_atom_intern("_UNIHAN_PREFEDIT", FALSE));

	commit_string_atom = gdk_atom_intern("_UNIHAN_COMMIT_STRING", FALSE);
	g_signal_connect(G_OBJECT(window->appletWindow), "selection-clear-event",
			 G_CALLBACK(commit_string_cleared), NULL);
	g_signal_connect(G_OBJECT(window->appletWindow), "selection-received",
			 G_CALLBACK(commit_string_received), NULL);
	gtk_selection_add_target(GTK_WIDGET(window->appletWindow), 
				 commit_string_atom,
				 gdk_atom_intern("UTF8_STRING", FALSE),
				 1);
	g_signal_connect(G_OBJECT(window->appletWindow), "realize",
			 G_CALLBACK(applet_window_realize), NULL);

	/* Register event handler */
	gdk_window_add_filter(window->appletWindow->window, xaux_ext_event_handler, 0);

        client = gconf_client_get_default();
        gconf_client_add_dir(client, UNIHAN_ROOT_KEY,
                        GCONF_CLIENT_PRELOAD_NONE, NULL);
        gconf_client_notify_add(client, STATUS_IM_ADD_KEY,
                        refresh_im_curr_list_add, NULL, NULL, NULL);
        gconf_client_notify_add(client, STATUS_IM_DEL_KEY,
                        refresh_im_curr_list_del, NULL, NULL, NULL);
	gconf_client_notify_add(client, STATUS_IM_SHIFT_UP,
			im_shift_up, NULL, NULL, NULL);
	gconf_client_notify_add(client, STATUS_IM_SHIFT_DOWN,
			im_shift_down, NULL, NULL, NULL);
        gconf_client_notify_add(client, PREFEDIT_COMMAND_KEY,
                        on_Prefedit_Command_toggled, NULL, NULL, NULL);
        gconf_client_notify_add(client, PREFEDIT_SYMBOL_DEL_KEY,
                        on_Prefedit_Symbol_Del_toggled, NULL, NULL, NULL);
        gconf_client_notify_add(client, PREFEDIT_WORD_DEL_KEY,
                        on_Prefedit_Word_Del_toggled, NULL, NULL, NULL);
        gconf_client_notify_add(client, PREFEDIT_UNISPIM_SET_KEY,
                        on_Prefedit_Unispim_set, NULL, NULL, NULL);
		gconf_client_notify_add(client, STATUS_IN_TRAY_KEY,
						on_Status_In_Tray_toggled, NULL, NULL, NULL);
		gconf_client_notify_add(client, TC_SC_KEY,
						on_tc_sc_changed, NULL, NULL, NULL);
	gconf_client_notify_add(client, PHRASE_MODE_KEY,
					on_phrase_mode_changed, NULL, NULL, NULL);
		gconf_client_notify_add(client, CHECK_MODULE_INFO_KEY,
						check_module_info, NULL, NULL, NULL);


	gconf_client_set_bool(client, "/extra/unispim/directory/key32", TRUE, NULL);
	gconf_client_set_bool(client, PREFEDIT_IM_CURR_LIST_PREPEND_KEY, False, NULL);
	if(gconf_client_get_bool(client,PREFEDIT_UNISPIM_SET_KEY,NULL))
		gconf_client_set_bool(client,PREFEDIT_UNISPIM_SET_KEY,FALSE,NULL);
	else
		gconf_client_set_bool(client,PREFEDIT_UNISPIM_SET_KEY,TRUE,NULL);

		find_system_tray();
		gboolean in_tray = gconf_client_get_bool(client, STATUS_IN_TRAY_KEY, NULL);
        if (in_tray) { 
       		window->runAsApplet = TRUE;
			gtk_widget_hide_all(window->appletWindow);
			gtk_widget_show_all(window->controls->hbox);
		}else {
			window->runAsApplet = FALSE;
			gtk_widget_hide_all(window->controls->hbox);
			gdk_window_raise(window->appletWindow->window);
			gtk_widget_show_all(window->appletWindow);
			hack_NET_SUPPORTED();
			gint x_coordinate = gconf_client_get_int(client, "/apps/sw-unihan/gnome_aux/status/x_coordinate", NULL);
			gint y_coordinate = gconf_client_get_int(client, "/apps/sw-unihan/gnome_aux/status/y_coordinate", NULL);
			gtk_window_move(GTK_WINDOW(window->appletWindow), x_coordinate, y_coordinate);
		}
		present_applet_window();
		gtk_selection_convert(window->appletWindow, commit_string_atom, 
							  gdk_atom_intern("UTF8_STRING", FALSE), GDK_CURRENT_TIME);
		gtk_timeout_add(7000, start_time_out, NULL);
		gtk_main();

        status_window_free(window);
        status_model_free(model);

	return 0;
}

static gboolean start_time_out(gpointer data)
{
	gdk_window_raise(window->appletWindow->window);
	gtk_widget_show_all(window->appletWindow);
	
	GConfClient *client = gconf_client_get_default();
	gboolean in_tray = gconf_client_get_bool(client, STATUS_IN_TRAY_KEY, NULL);
	if (in_tray) { 
       	window->runAsApplet = TRUE;
		gtk_widget_hide_all(window->appletWindow);
		gtk_widget_show_all(window->controls->hbox);
	}else {
		window->runAsApplet = FALSE;
		gtk_widget_hide_all(window->controls->hbox);
		gdk_window_raise(window->appletWindow->window);
		gtk_widget_show_all(window->appletWindow);
		gint x_coordinate = gconf_client_get_int(client, "/apps/sw-unihan/gnome_aux/status/x_coordinate", NULL);
		gint y_coordinate = gconf_client_get_int(client, "/apps/sw-unihan/gnome_aux/status/y_coordinate", NULL);
		gtk_window_move(GTK_WINDOW(window->appletWindow), x_coordinate, y_coordinate);
	}
	present_applet_window();
	hack_NET_SUPPORTED();

	return FALSE;
}

static gboolean write_coordinates(gpointer data)
{
	GConfClient *client = gconf_client_get_default();
	gint x_coordinate;
	gint y_coordinate;
	gtk_window_get_position(GTK_WINDOW(window->appletWindow), &x_coordinate, &y_coordinate);
	gconf_client_set_int(client, "/apps/sw-unihan/gnome_aux/status/x_coordinate", x_coordinate, NULL);
	gconf_client_set_int(client, "/apps/sw-unihan/gnome_aux/status/y_coordinate", y_coordinate, NULL);
	return TRUE;
}
		
static gboolean clean_timer_for_moving(gpointer data)
{
	if (timer_for_moving)
		gtk_timeout_remove(timer_for_moving);
	return FALSE;
}

/* the following function is same as that in xaux_ext_lookup.c,
 * in fact, it just a copy.
 * I think xaux_ext_lookup & xaux_ext_status had better be indenpent
 * with each other when compiling,
 * So ............
 */
static void
hack_NET_SUPPORTED(void)
{
	Atom *atoms = NULL;
	gulong n_atoms = 0;
	GdkAtom xproperty_ga;
	Atom xproperty = None;
	Atom tmp_xproperty = None;
	Atom type;
	gint format;
	//gulong nitems;
	gulong bytes_after;
	gulong i;
	Atom wmspec_supported_atom;

	/* don't create the atoms if they don't already exist! */
	gdk_error_trap_push();
	xproperty_ga = gdk_atom_intern("_NET_WM_MOVERESIZE", TRUE);
	if (xproperty_ga != GDK_NONE)
		xproperty = gdk_x11_atom_to_xatom(xproperty_ga);
	tmp_xproperty = gdk_x11_atom_to_xatom(gdk_atom_intern("_NET_WM_MOVERESIZE_T", FALSE));

	wmspec_supported_atom = //gdk_x11_get_xatom_by_name ("_NET_SUPPORTED");
				XInternAtom(gdk_display, "_NET_SUPPORTED", True);
        gdk_flush();
	if (gdk_error_trap_pop() != 0)
		return;

	/* these atoms don't always exist, eg. when no WM is running... */
	if (wmspec_supported_atom == None)
		return;
	if (xproperty == None)
		return;

        XGetWindowProperty (gdk_display, DefaultRootWindow(gdk_display),
                        wmspec_supported_atom , 0, G_MAXLONG,
                        False, XA_ATOM, &type, &format, &n_atoms,
                        &bytes_after, (guchar **)&atoms);

	for ( i = 0; i < n_atoms; i++ )
        {
                if (atoms[i] == xproperty)
                {
                        atoms[i] = tmp_xproperty;
			break;
                }
        }

	XChangeProperty(gdk_display, DefaultRootWindow(gdk_display),
			wmspec_supported_atom,
			type, format, PropModeReplace, (unsigned char*)atoms, n_atoms);
}

/* ========================================================================= */
/* ==================== X Auxilliary Objects related ======================= */
/* ========================================================================= */
Bool
xaux_ext_Start(xaux_class_t *xc, aux_ext_data_t *aux_ext_data, Atom atom)
{
	int int_list[2];
	char *str_list[1];
 
	//fprintf(stderr, "Enter xaux_ext_Start.\n\r"); 
 
        // FIXME: here we assume the first time xaux_ext_Start() gets called 
        //        is by htt_xbe
        if (xbe_im == VOID_IM_ID) {
                xbe_im = aux_ext_data->im;
                xbe_ic = aux_ext_data->ic;
        }
	
	im_ = aux_ext_data->im;
	ic_ = aux_ext_data->ic;
	xc_ = xc;
	if (! ic_)
		DEBUG_LOG("ic NULL ...\n");


	/* tell them we're here, and send Product Key to them */
	int_list[0] = UNIHAN_AUX_STATUS_START_NOTIFY;
	send_to_engine(1, int_list, 0, NULL);

	/* FIXME: actually send Product Key here */
	/* if first run, start druid */

	/* tell them what we're made of ;) */
	int_list[0] = UNIHAN_ENGINE_SET_ENCODING;
	str_list[0] = orig_codeset;
	send_to_engine(1, int_list, 1, str_list);

	/* request list of IMs available */
	int_list[0] = UNIHAN_ENGINE_GET_IM_LIST;
	send_to_engine(1, int_list, 0, NULL);
    //printf("gets the imlist\n\r");
#if 0
	send_word_list_to_engine(model->wordList);
	send_symbol_list_to_engine(model->symbolList);
#endif
	im_ = VOID_IM_ID;
	ic_ = VOID_IC_ID;
	return True;
}

/* ------------------------------------------------------------------------- */
Bool
xaux_ext_Draw_real(xaux_class_t *xc, aux_ext_data_t *aux_ext_data)
{ 
	int type;
	
	im_ = aux_ext_data->im;
	ic_ = aux_ext_data->ic;
	xc_ = xc;

	if (aux_ext_data->integer_count < 1)
		return False;

	type = aux_ext_data->integer_list[0];
	switch (type) {
		case UNIHAN_ENGINE_GET_IM_LIST:
			DEBUG_LOG("run the UNIHAN_ENGINE_GET_IM_LIST\n\r");
			receive_im_list(aux_ext_data);
			status_unihan_available_set(model, TRUE);
			GConfClient *client = gconf_client_get_default();
			gboolean in_tray = gconf_client_get_bool(client, STATUS_IN_TRAY_KEY, NULL);
			if (in_tray) {
				window->runAsApplet = TRUE;
				gtk_widget_hide_all(window->appletWindow);
				gtk_widget_show_all(window->controls->hbox);
			}else {
				window->runAsApplet = FALSE;
				gtk_widget_hide_all(window->controls->hbox);
				gdk_window_raise(window->appletWindow->window);
				gtk_widget_show_all(window->appletWindow);
				hack_NET_SUPPORTED();
				gint x_coordinate = gconf_client_get_int(client, "/apps/sw-unihan/gnome_aux/status/x_coordinate", NULL);
				gint y_coordinate = gconf_client_get_int(client, "/apps/sw-unihan/gnome_aux/status/y_coordinate", NULL);
				gtk_window_move(GTK_WINDOW(window->appletWindow), x_coordinate, y_coordinate);
			}
			present_applet_window();
			break;

#if TIMEBOMB
                case UNIHAN_ENGINE_DEMO_EXPIRED:
                        if (aux_ext_data->integer_count < 3)
                                return False;
                        
                        // uh-oh
                        expired = aux_ext_data->integer_list[1];
                        expire_date = (time_t)aux_ext_data->integer_list[2];
                        if (expired != 0)
                                demo_expired();
                        break;
#endif
		case UNIHAN_ENGINE_INVALID_KEY:
			// FIXME: run druid with `invalid key'
			break;

		case UNIHAN_AUX_STATUS_PREV_IM:
		/*{
#if NEW_PROPERTY
		
			UnihanPropertyArgList pp = NULL;
			printf("Get property count: %d\n\r",aux_ext_data->string_count-1);
			pp = convert_string_to_properties(aux_ext_data);
			printf("get propertylis\n\r");
			break;
		}
#endif	*/
		case UNIHAN_AUX_STATUS_NEXT_IM: {
			int int_values[1];
			char *string_values[1];
			int_values[0] = UNIHAN_ENGINE_CHECK_MODULE_INFO;
			//send_to_engine(1, int_values, 0, NULL);
			GList *im = model->imCurrList;
			IMInfo *info = NULL;

			DEBUG_LOG("run the UNIHAN_AUX_STATUS_NEXT_IM\n\r");

			/* english : toggle im and switch */
			/*if (!model->currIM) {
				im = model->imCurrList;
				if (type == UNIHAN_AUX_STATUS_PREV_IM) {
					while (im->next)
						im = g_list_next(im);
				}
				info = (IMInfo *)im->data;
				int_values[0] = UNIHAN_ENGINE_SWITCH_IM;
				string_values[0] = info->id;
				send_to_engine(1, int_values, 1, string_values);
				break;
			}*/
			while (im) {
				info = (IMInfo *)im->data;
				if (!model->currIM || !model->currIM->id) {
					int_values[0] = UNIHAN_ENGINE_CONV_OFF;
					send_to_engine(1, int_values, 0, NULL);
					return False;
				}
				if (g_ascii_strcasecmp(info->id, model->currIM->id) == 0) {
					break;
				}
				im = g_list_next(im);
			}
			if (!im) {
				int_values[0] = UNIHAN_ENGINE_CONV_OFF;
				send_to_engine(1, int_values, 0, NULL);
				return False;
			}

			if (type == UNIHAN_AUX_STATUS_NEXT_IM) {
				im = g_list_next(im);
				if (!im)
					im = model->imCurrList;
			}
			else {
				im = g_list_previous(im);
				if (!im) {
					im = model->imCurrList;
					while (im->next)
						im = g_list_next(im);
				}
			}

			info = (IMInfo *)im->data;
			
			string_values[0] = info->id;
			int_values[0] = UNIHAN_ENGINE_SWITCH_IM;

			send_to_engine(1, int_values, 1, string_values);

			break;
		}
#if NEW_PROPERTY
		case UNIHAN_AUX_PROPERTY_REGISTER:{
			DEBUG_LOG("Get property count: %d\n\r",aux_ext_data->string_count-1);
			UnihanPropertyList *pp = convert_string_to_properties_list(aux_ext_data);
			DEBUG_LOG("the propertiesNum is %d\n\r", pp->propertiesNum);
			//pp = convert_string_to_properties_list(aux_ext_data);
			//printf("Get property count: %d\n\r",aux_ext_data->string_count-1);
			window->model->currIM->propertyList = convert_string_to_properties(aux_ext_data);
			//UnihanProperty *ps = convert_string_to_properties(aux_ext_data);
			//printf("the label is %s\n\r", ps->label);
			property_tree = status_model_retreive_property_list(pp);
			DEBUG_LOG("the tree is created\n\r");
			break;
		}
#endif		
		 case UNIHAN_AUX_UNSET_FOCUS:
			tv.tv_sec=0;
			tv.tv_usec=50000;
			select(1,NULL,NULL,NULL,&tv);
			
			if (!click_status) {
				if (window->runAsApplet) {	
					gtk_widget_hide(window->controls->widthButton);
					gtk_widget_hide(window->controls->puncceButton);
					gtk_widget_hide(window->controls->tcscButton);
					gtk_widget_hide(window->controls->imButton);
					gtk_widget_show(window->controls->icon);
				}else {
					status_model_current_im_set_by_id(model, "English");
					present_applet_window();
				}
				unset_focus_before=1;
			}
			break;

		case UNIHAN_AUX_STATUS_SWITCH_IM: {
			int int_values[1];
			char *string_values[1];
			int_values[0] = UNIHAN_ENGINE_CHECK_MODULE_INFO;
			//send_to_engine(1, int_values, 0, NULL);
			GList *im = model->imCurrList;
			IMInfo *info = NULL;

			click_status=0;
			unset_focus_before=0;
			
			//int int_values[1];
			DEBUG_LOG("run the UNIHAN_AUX_STATUS_SWITCH_IM\n\r");
#if NEW_PROPERTY
			IMInfo *info_curr_list = NULL;
			//UnihanProperty *unihan_curr_property;
#endif
			//char *string_values[1];
			gchar *im_id = aux_ext_data->string_list[0].ptr;
			DEBUG_LOG("curr_id is %s\n\r", im_id);
			if (aux_ext_data->string_count < 1)
				return False;

			focused = TRUE;
			focused_im = im_;
			focused_ic = ic_;
			if (g_ascii_strcasecmp(im_id, "English")) {
				while (im) {
					info = (IMInfo *)im->data;
					if (g_ascii_strcasecmp(info->cname, im_id) == 0) {
						break;
					}
					im = g_list_next(im);
				}
				if (!im) {
					im = model->imCurrList;
					info = (IMInfo *)im->data;
					int_values[0] = UNIHAN_ENGINE_SWITCH_IM;
					string_values[0] = info->id;
					send_to_engine(1, int_values, 1, string_values);
					return False;
				}
			}
			
#if NEW_PROPERTY
		    //IMInfo *info = (IMInfo*)imlist;
			if (imlist != NULL)
			{
				while(imlist)
			    {
					info_list = (IMInfo *)imlist->data;
					
				    if (strcmp(info_list->id, im_id))
				    {
					    info_curr_list = info_list;
				    }
				    imlist = imlist->next;
			    }
		    }
			DEBUG_LOG("info_curr_list is %s\n\r", info_list->cname);
			//if (strcmp(info_list->id, im_id))
			//{
                if (info_list->propertyList != NULL)
			    {
					DEBUG_LOG("the model->currIM->currIM_property_list is true\n\r");
				    int depth;
				    depth = g_node_depth(property_tree->root);
				    //g_node_traverse(property_tree, G_LEVEL_ORDER, G_TRAVERSE_ALL, depth, gnode_traverse_fun, NULL);*/
			    }
			    else
			    {
					string_values[0] = info_list->id;
					DEBUG_LOG("send UNIHAN_ENGINE_PROPERTY_REGISTER to le %s\n\r", string_values[0]);
				    int_values[0] = UNIHAN_ENGINE_PROPERTY_REGISTER;
				    send_to_engine(1, int_values, 1, string_values);
			    }
		    //}
#endif
#if NEW_PROPERTY
			if (imflag == 1)
			{
				gtk_widget_show(window->controls->imButton);
				gtk_widget_hide(window->controls->icon);
				imflag = 0;
				//status_model_current_im_set_by_id(model, cname);
			}
			
			if (!strcmp("English", aux_ext_data->string_list[0].ptr))
			{
				gtk_widget_show(window->controls->icon);
				gtk_widget_hide(window->controls->imButton);
				DEBUG_LOG("set english_im_flag is %d\n\r", english_im_flag);
				imflag = 1;
			}
#endif

			status_model_current_im_set_by_id(model, im_id);
			// FIXME:
			// check for English/HW, start timer to hide at timeout if so
			// (NOTE : I think English/HW should not be set here, le controls them.
			// So do I . Arren)
			present_applet_window();
			break;
		}
		case UNIHAN_AUX_STATUS_BEEP:
			if (beep_on_error)
				gdk_beep();
			break;
#if NEW_PROPERTY
#else
		case UNIHAN_AUX_STATUS_FULLWIDTH:
			status_fullwidth_set(model, TRUE);
			DEBUG_LOG("here is set full/half mode\n");
			present_applet_window();
			break;

		case UNIHAN_AUX_STATUS_HALFWIDTH:
			status_fullwidth_set(model, FALSE);
			// FIXME:
			// check for English/HW, start timer to hide at timeout if so
			// (NOTE : I think English/HW should not be set here, le controls them.
			// So do I. Arren)
			present_applet_window();
			break;

                case UNIHAN_AUX_STATUS_ENGLISHPUNC:
                        status_puncce_set(model, FALSE);
                        present_applet_window();
                        break;

                case UNIHAN_AUX_STATUS_CHINESEPUNC:
                        status_puncce_set(model, TRUE);
                        present_applet_window();
                        break;

		case UNIHAN_AUX_STATUS_TCSC_MODE:
			if (aux_ext_data->integer_count < 2)
				return False;
			receive_tcsc_mode(aux_ext_data);
			break;

		case UNIHAN_AUX_STATUS_PUNC_KEYBOARD:
			if (aux_ext_data->integer_count < 2)
				return False;
			if (punc_kbd_item != NULL) {	/* is NULL if menu has not been used */
				DEBUG_LOG("Set punc_kbd_item to %d", aux_ext_data->integer_list[1]);

				if (!click_status) {
					g_signal_handler_block(punc_kbd_item, punc_kbd_item_handler_id);
					gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(punc_kbd_item),
												   aux_ext_data->integer_list[1] == 1 ? TRUE : FALSE);
					g_signal_handler_unblock(punc_kbd_item, punc_kbd_item_handler_id);
				}
			}
			break;

		case UNIHAN_AUX_STATUS_US_KEYBOARD:
			if (aux_ext_data->integer_count < 2)
				return False;
			if (us_kbd_item != NULL) {		/* is NULL if menu has not been used */
				DEBUG_LOG("Set us_kbd_item to %d", aux_ext_data->integer_list[1]);

				if (!click_status) {
					g_signal_handler_block(us_kbd_item, us_kbd_item_handler_id);
					gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(us_kbd_item),
												   aux_ext_data->integer_list[1] == 1 ? TRUE : FALSE);
					g_signal_handler_unblock(us_kbd_item, us_kbd_item_handler_id);
				}
			}
			break;
		//case UNIHAN_AUX_GET_FOCUS:
#endif
		case UNIHAN_AUX_LOST_FOCUS:
			DEBUG_LOG("UNIHAN_AUX_LOST_FOCUS\n");
			//set to English, because no UNIHAN_AUX_GET_FOCUS, so do not set, otherwise
			//GET_FOCUS will not work.
			//status_model_current_im_set_by_id(model, "English");
			// FIXME:
			// check for English/HW, start timer to hide at timeout if so
			//present_applet_window();

			// ignore spurious lost focus events
			if ((ic_ != focused_ic) || (im_ != focused_im))
				break;
			focused = FALSE;

			// start a timer, if still not focused to a client at timeout,
			// then do something... hide, for example
			// popping up a GtkMenu grabs keyboard focus... any way to disable that?
			focus_lost_timer = g_timeout_add(200, lost_focus_timeout, NULL);
			break;
		default:
			break;
	}
	return True;
}

/* ------------------------------------------------------------------------- */
Bool
xaux_ext_Draw(xaux_class_t *xc, aux_ext_data_t *aux_ext_data, Atom atom)
{
	Bool ret = xaux_ext_Draw_real(xc, aux_ext_data);
	//im_ = VOID_IM_ID;
	//ic_ = VOID_IC_ID;
	return ret;
}


/* ------------------------------------------------------------------------- */
Bool
xaux_ext_Done(xaux_class_t *xc, aux_ext_data_t *aux_ext_data, Atom atom)
{
	gtk_main_quit();
	return True;
}

/* ------------------------------------------------------------------------- */
void
send_to_engine(int int_count, int *ints, int str_count, char **strs)
{
	int i;
	aux_ext_data_t *aux_data;

	if (im_ == VOID_IM_ID || ic_ == VOID_IC_ID || !xc_)
		return;

	if (!int_count && !str_count)
		return;

	aux_data = g_new0(aux_ext_data_t, 1);

	aux_data->im = im_;
	aux_data->ic = ic_;
	aux_data->integer_count = int_count;
	aux_data->string_count = str_count;

	if (aux_data->integer_count) {
		aux_data->integer_list = g_new0(int, aux_data->integer_count);
		for (i = 0; i < aux_data->integer_count; i++) {
			aux_data->integer_list[i] = ints[i];
		}
	}

	if (aux_data->string_count) {
		aux_data->string_list = g_new0(aux_ext_string_t, aux_data->string_count);
		for (i = 0; i < aux_data->string_count; i++) {
			aux_ext_string_t *p = &aux_data->string_list[i];
			p->length = strlen(strs[i]);
			p->ptr = (unsigned char *)strdup(strs[i]);
		}
	}

	gdk_error_trap_push();
	xaux_ext_SetValue(GDK_WINDOW_XDISPLAY(window->appletWindow->window), xc_, aux_data);
	XFlush(GDK_WINDOW_XDISPLAY(window->appletWindow->window));
	if (gdk_error_trap_pop() != 0) {
		// BadWindow? we've lost xaux.so...
		im_ = VOID_IM_ID;
		ic_ = VOID_IC_ID;
		xc_ = NULL;
	}

	if (aux_data->integer_list)
		g_free(aux_data->integer_list);
	if (aux_data->string_list) {
		for (i = 0; i < aux_data->string_count; i++) {
			aux_ext_string_t *p = &aux_data->string_list[i];
			if (p && p->ptr)
				g_free(p->ptr);
		}
		g_free(aux_data->string_list);
	}
	g_free(aux_data);
}

/* ------------------------------------------------------------------------- */
static GdkFilterReturn
xaux_ext_event_handler(GdkXEvent *gdk_xevent, GdkEvent *event, gpointer user_data)
{
	XEvent *xevent = (XEvent *) gdk_xevent;

        switch (xevent->type) {
                case ClientMessage:
			gdk_error_trap_push();
                        xaux_ext_process_client_message((Display *)gdk_display,
                                (XClientMessageEvent *) xevent);
			gdk_error_trap_pop();
                        break;
                case SelectionClear:
                        break;
        }
        return GDK_FILTER_CONTINUE;
}


/* ========================================================================= */
/* ==================== Unihan state model ================================= */
/* ========================================================================= */
static StatusModel *
status_model_init(void)
{
        StatusModel *m = g_new0(StatusModel, 1);
        m->fullwidth = FALSE;
        m->tcsc = UNIHAN_TCSC_NO_CONV;
        m->puncce = FALSE;
        //StatusModel *m = g_new0(StatusModel, 1);
        //if (is_unicode_charset(orig_codeset)) {
          //      m->tcscAvailable = TRUE;
        //}
	//m->fullwidth = FALSE;
	//m->tcsc = UNIHAN_TCSC_NO_CONV;
	//m->puncce = FALSE;
	if (is_unicode_charset(orig_codeset)) {
		m->tcscAvailable = TRUE;
	}

#if 0
	m->symbolList = Symbol_get_list_from_conf_file();
	m->wordList = Word_get_list_from_conf_file();
#endif

	return m;
}

/* ------------------------------------------------------------------------- */
static void
status_model_free(StatusModel *m)
{
	free_im_list(m->imList);
        free_im_list(m->imCurrList);
#if 0
        g_list_free(m->symbolList);
        g_list_free(m->wordList);
#endif
        g_free(m);
}

/* ------------------------------------------------------------------------- */
static void
status_model_im_curr_list_set(StatusModel *m, GList *new_imCurrList)
{
        if (m->imCurrList) {
                free_im_list(m->imCurrList);
        }

        m->imCurrList = new_imCurrList;
}

/* ------------------------------------------------------------------------- */
static void
status_model_im_list_set(StatusModel *m, GList *new_imList)
{
	//gchar *prevIM = NULL;
#if 1
	//gchar prevIM[20];
	gchar *prevIM = NULL;

	if (m->imList) {
		// preserve the current IM selection!
		//strcpy(prevIM, "English");
		prevIM = strdup("English");
		if (m->currIM) {
			//prevIM = m->currIM->cname;
			//strcpy(prevIM, m->currIM->cname);
			prevIM = strdup(m->currIM->cname);
		}
		free_im_list(m->imList);
	}

	m->imList = new_imList;
	m->currIM = NULL;

	if (prevIM) {
		status_model_current_im_set_by_id(m, prevIM);
	}
#else
	gchar *prevIM = NULL;

        if (m->imList) {
                // preserve the current IM selection!
                gchar *prevIM = "English";
                if (m->currIM) {
                        prevIM = m->currIM->cname;
                }
                
                free_im_list(m->imList);
        }

        m->imList = new_imList;
        m->currIM = NULL;

        if (prevIM) {
                status_model_current_im_set_by_id(m, prevIM);
		}
#endif

}

/* ------------------------------------------------------------------------- */
static void
status_model_current_im_set_by_id(StatusModel *m, gchar *im_id)
{
	IMInfo *newIM = NULL;
	char strKana[7]={0xe5,0x81,0x87,0xe5,0x90,0x8d,0};

	if (!strcmp("English", im_id)) {
		m->language=0;
		newIM = NULL;
	} else {
		if ((!strcmp(strKana, im_id))
		||(!strcmp("Unicode", im_id))
		||(!strcmp("Canna", im_id)))
			m->language=2;
		else
			m->language=1;
		GList *imList_ = m->imList;
		while (imList_) {
			IMInfo *im = (IMInfo *)imList_->data;
			if (!strcmp(im->cname, im_id)) {
				newIM = im;
				break;
			}
			imList_ = imList_->next;
		}
	}
	if (newIM != m->currIM) {
		m->currIM = newIM;
	}
	controls_current_im_updated(m->currIM);
}

/* ------------------------------------------------------------------------- */
#if NEW_PROPERTY
#else
static void
status_puncce_set(StatusModel *m, gboolean is_cp)
{
        if (m->puncce != is_cp) {
                m->puncce = is_cp;
        }

        controls_puncce_updated(is_cp);
}
#endif
/*static char *
status_get_next_im_by_id(StatusModel *m, char *id)
{
	char *id_next;
	GList *im_list = m->imList;
	GList *im_curr_list = m->imCurrList;
	IMInfo *info_curr = NULL;
	IMInfo *info = NULL;
	gboolean found = FALSE;

	while(im_list) {
		info = (IMInfo *)im_list->data;
		if (g_ascii_strcasecmp(info->cname, id) == 0)
			break;
		im_list = g_list_next(im_list);
	}

	im_list = g_list_next(im_list);
	if (!im_list)
		im_list = m->imList;

	while (im_list) {
		info = (IMInfo *)im_list->data;
		im_curr_list = m->imCurrList;
		while (im_curr_list) {
			info_curr = (IMInfo *)im_curr_list->data;
			if (g_ascii_strcasecmp(info->cname, info_curr->cname) == 0) {
				found = TRUE;
				break;
			}
			im_curr_list = g_list_next(im_curr_list);
			//if (!im_curr_list)
			//	im_curr_list = m->imCurrList;
		}
		if (found)
			break;
		im_list = g_list_next(im_list);
		if (!im_list)
			im_list = m->imList;
	}
	id_next = info_curr->id;
	return id_next;
}*/

/* ------------------------------------------------------------------------- */
#if NEW_PROPERTY
#else
static void
status_fullwidth_set(StatusModel *m, gboolean is_fullwidth)
{
        if (m->fullwidth != is_fullwidth) {
                m->fullwidth = is_fullwidth;
        }

        controls_fullwidth_updated(is_fullwidth);
}
#endif

/* ------------------------------------------------------------------------- */
#if NEW_PROPERTY
#else
static void
status_model_tcsc_mode_set(StatusModel *m, UnihanTCSCMode tcsc)
{
        if (m->tcscAvailable == FALSE)
                tcsc = UNIHAN_TCSC_NO_CONV;

        if (m->tcsc != tcsc) {
                m->tcsc = tcsc;
        }

        controls_tcsc_mode_updated(tcsc);
}
#endif
/* ------------------------------------------------------------------------- */
static void
status_unihan_available_set(StatusModel *m, gboolean avail)
{
#if TIMEBOMB
        if (expired)    // Unihan never starts!
                avail = FALSE;
#endif

        if (m->unihanAvailable != avail) {
                m->unihanAvailable = avail;
        }

        controls_unihan_available(avail);
}

/* ------------------------------------------------------------------------- */
/*static void
status_punc_mode_set(StatusModel *m, gboolean punc)
{
        if (m->puncMode != punc) {
                m->puncMode = punc;
        }
}

*/
/* ========================================================================= */
/* ==================== Widgets creation =================================== */
/* ========================================================================= */
static GtkWidget *
create_unihan_icon(void)
{
	GtkWidget *w = gtk_event_box_new();
	GtkWidget *pix = gtk_image_new_from_file(UNIHAN_DATA_DIR "/images/icon.png");
	g_signal_connect(G_OBJECT(w), "button_press_event", G_CALLBACK(icon_press_handler), NULL);
	gtk_container_add(GTK_CONTAINER(w), pix);
        return w;
}

/* ------------------------------------------------------------------------- */
/*#if NEW_PROPERTY
static GtkWidget *
create_property_button(GtkLabel *unihanlabel, char *callback)
{
	GtkWidget *w = gtk_button_new();
	gtk_button_set_relief(GTK_BUTTON(w), GTK_RELIEF_NONE);
	gtk_container_add(GTK_CONTAINER(w), GTK_WIDGET(unihanlabel));
	gtk_tooltips_set_tip(tooltips, w, prolist->properties->tip, NULL);
	g_signal_connect(G_OBJECT(w), "button_press_event", G_CALLBACK(callback), NULL);
	gtk_widget_show(w);
	return w;
}
static GtkWidget *
create_image_button(UnihanPropertyList prolist, char *callback)
{
	GtkImage *image = gtk_image_new_from_file(prolist->properties->icon);
	GtkWidget *w = gtk_button_new();
    gtk_button_set_relief(GTK_BUTTON(w), GTK_RELIEF_NONE);
	gtk_container_add(GTK_CONTAINER(w), image);
	gtk_tooltips_set_tip(tooltips, w, prolist->properties->tip, NULL);
	g_signal_connect(G_OBJECT(w), "button_press_event", G_CALLBACK(callback), NULL);
    gtk_widget_show(w);
	return w;	
}
static GtkWidget *
create_property_label(UnihanPropertyList pplist)
{
	return gtk_label_new(pplist->properties->label);
}
static void
hide_im_button()
{
	gtk_widget_hide(window->controls->imButton);
}*/

static GtkWidget *
create_im_label(void)
{
        return gtk_label_new(_("English"));
}

/* ------------------------------------------------------------------------- */
static GtkWidget *
create_im_button(GtkLabel *im_label)
{
	GtkWidget *w = gtk_button_new();
	gtk_button_set_relief(GTK_BUTTON(w), GTK_RELIEF_NONE);
	g_object_set(G_OBJECT(w), "can-focus", FALSE, NULL);
	gtk_container_add(GTK_CONTAINER(w), GTK_WIDGET(im_label));
	g_signal_connect(G_OBJECT(w), "clicked",
			 G_CALLBACK(popup_im_menu_from_im_button), NULL);
        return w;
}
#if NEW_PROPERTY
#else
/* ------------------------------------------------------------------------- */
static GtkWidget *
create_width_label(void)
{
        return gtk_label_new(_("HW"));
}

/* ------------------------------------------------------------------------- */
static GtkWidget *
create_width_button(GtkLabel *w_label)
{
        GtkWidget *w = gtk_button_new();
	gtk_button_set_relief(GTK_BUTTON(w), GTK_RELIEF_NONE);
	g_object_set(G_OBJECT(w), "can-focus", FALSE, NULL);
	gtk_container_add(GTK_CONTAINER(w), GTK_WIDGET(w_label));
	gtk_tooltips_set_tip(tooltips, w, _("Toggle halfwidth/fullwidth mode"), NULL);
	g_signal_connect(G_OBJECT(w), "clicked",
			 G_CALLBACK(toggle_width_handler), NULL);
        return w;
}

/* ------------------------------------------------------------------------- */
static GtkWidget *
create_tcsc_label(void)
{
        return gtk_label_new(_("NoConv"));
}

/* ------------------------------------------------------------------------- */
static GtkWidget *
create_tcsc_button(GtkLabel *tcsc_label)
{
        GtkWidget *w = gtk_button_new();
	gtk_button_set_relief(GTK_BUTTON(w), GTK_RELIEF_NONE);
	g_object_set(G_OBJECT(w), "can-focus", FALSE, NULL);
	gtk_container_add(GTK_CONTAINER(w), GTK_WIDGET(tcsc_label));

        gtk_tooltips_set_tip(tooltips, w, _("Change Traditional/Simplified Chinese conversion mode"), NULL);
        
	g_signal_connect(G_OBJECT(w), "clicked",
			 G_CALLBACK(tcsc_item_activate), NULL);
	g_signal_connect(G_OBJECT(w), "pressed",
		         G_CALLBACK(applet_tcsc_button_pressed_event_handler), NULL);
        return w;
}

/* ------------------------------------------------------------------------- */
static GtkWidget *
create_puncce_label(void)
{
        return gtk_label_new(_("EP"));
}

/* ------------------------------------------------------------------------- */
static GtkWidget *
create_puncce_button(GtkLabel *puncce_label)
{
        GtkWidget *w = gtk_button_new();
	gtk_button_set_relief(GTK_BUTTON(w), GTK_RELIEF_NONE);
	g_object_set(G_OBJECT(w), "can-focus", FALSE, NULL);
	gtk_container_add(GTK_CONTAINER(w), GTK_WIDGET(puncce_label));
        gtk_tooltips_set_tip(tooltips, w, _("Toggle Chinese/English punctuation mode"), NULL);
	g_signal_connect(G_OBJECT(w), "clicked",
			 G_CALLBACK(toggle_puncce_handler), NULL);
        return w;
}

/* ------------------------------------------------------------------------- */
static GtkWidget *
create_tcsc_menu(void)
{
	GtkWidget *menu = gtk_menu_new();
	g_signal_connect(G_OBJECT(menu), "deactivate",
			 G_CALLBACK(applet_tcsc_menu_deactivate_event_handler), NULL);

        GtkWidget *mitem;
        GSList *group = NULL;
        mitem = gtk_radio_menu_item_new_with_mnemonic(group, _("_No conversion"));
        group = gtk_radio_menu_item_get_group(GTK_RADIO_MENU_ITEM(mitem));
        g_signal_connect(G_OBJECT(mitem), "activate",
                         G_CALLBACK(tcsc_item_handler), GINT_TO_POINTER(0));
        gtk_menu_shell_append(GTK_MENU_SHELL(menu), mitem);
        mitem = gtk_radio_menu_item_new_with_mnemonic(group, _("_Traditional -> simplified"));
        group = gtk_radio_menu_item_get_group(GTK_RADIO_MENU_ITEM(mitem));
        g_signal_connect(G_OBJECT(mitem), "activate",
                         G_CALLBACK(tcsc_item_handler), GINT_TO_POINTER(1));
        gtk_menu_shell_append(GTK_MENU_SHELL(menu), mitem);
        mitem = gtk_radio_menu_item_new_with_mnemonic(group, _("_Simplified -> traditional"));
        g_signal_connect(G_OBJECT(mitem), "activate",
                         G_CALLBACK(tcsc_item_handler), GINT_TO_POINTER(2));
        gtk_menu_shell_append(GTK_MENU_SHELL(menu), mitem);

	g_object_set(G_OBJECT(menu), "can-focus", False, NULL);

        return menu;
}
#endif

/* ------------------------------------------------------------------------- */
static GtkWidget *
create_main_menu(void)
{
        GtkWidget *menu = gtk_menu_new();
	GtkWidget *mitem = gtk_image_menu_item_new_from_stock(GTK_STOCK_PREFERENCES, NULL);
	g_signal_connect(G_OBJECT(mitem), "activate",
			 G_CALLBACK(pref_item_handler), NULL);
	gtk_menu_shell_append(GTK_MENU_SHELL(menu), mitem);

	mitem = gtk_separator_menu_item_new();
	gtk_menu_shell_append(GTK_MENU_SHELL(menu), mitem);
	mitem = gtk_image_menu_item_new_from_stock(GTK_STOCK_ABOUT, NULL);
	g_signal_connect(G_OBJECT(mitem), "activate",
			 G_CALLBACK(about_item_handler), NULL);
	gtk_menu_shell_append(GTK_MENU_SHELL(menu), mitem);
	gtk_widget_show_all(menu);

	g_object_set(G_OBJECT(menu), "can-focus", False, NULL);

        return menu;
}

/* ------------------------------------------------------------------------- */
static StatusControls *
status_controls_new(StatusWindow *w)
{
	StatusControls *c = g_new0(StatusControls, 1);

	c->hbox = gtk_hbox_new(FALSE, 0);

	// Unihan Logo
	c->iconbox = gtk_hbox_new(FALSE, 0);
    //c->icon = create_unihan_icon();
	c->icon = create_unihan_icon();
	g_object_set(G_OBJECT(c->icon), "can-focus", FALSE, NULL);
	gtk_box_pack_start(GTK_BOX(c->iconbox), c->icon, FALSE, FALSE, 0);
	gtk_box_pack_start(GTK_BOX(c->hbox), c->iconbox, FALSE, FALSE, 0);
	// IM selection menu
//#if NEW_PROPERTY
//#else
	c->imbox = gtk_hbox_new(FALSE, 0);
    c->imLabel = create_im_label();
    //c->imLabel = create_im_label();
	g_object_set(G_OBJECT(c->imLabel), "can-focus", FALSE, NULL);
    c->imButton = create_im_button(GTK_LABEL(c->imLabel));
	gtk_box_pack_start(GTK_BOX(c->imbox), c->imButton, FALSE, FALSE, 0);
	gtk_box_pack_start(GTK_BOX(c->hbox), c->imbox, FALSE, FALSE, 0);
	//gtk_widget_hide(c->imButton);

#if NEW_PROPERTY
#else
	// fullwidth toggle
	c->widthLabel = create_width_label();
	g_object_set(G_OBJECT(c->widthLabel), "can-focus", FALSE, NULL);
	c->widthButton = create_width_button(GTK_LABEL(c->widthLabel));
	g_object_set(G_OBJECT(c->widthButton), "can-focus", FALSE, NULL);
	gtk_box_pack_start(GTK_BOX(c->hbox), c->widthButton, FALSE, FALSE, 0);

	// puncce toggle
	c->puncceLabel = create_puncce_label();
	c->puncceButton = create_puncce_button(GTK_LABEL(c->puncceLabel));
	gtk_box_pack_start(GTK_BOX(c->hbox), c->puncceButton, FALSE, FALSE, 0);

	// tcsc menu
	c->tcscLabel = create_tcsc_label();
	c->tcscButton = create_tcsc_button(GTK_LABEL(c->tcscLabel));
	gtk_box_pack_start(GTK_BOX(c->hbox), c->tcscButton, FALSE, FALSE, 0);
#endif

	gboolean avail = w->model->unihanAvailable;
	gtk_widget_set_sensitive(c->imButton, avail);
#if NEW_PROPERTY
#else
	gtk_widget_set_sensitive(c->widthButton, avail);
	gtk_widget_set_sensitive(c->puncceButton, avail);
        if (model->tcscAvailable)
                gtk_widget_set_sensitive(c->tcscButton, avail);
#endif
#if NEW_PROPERTY
#else
	gtk_widget_set_sensitive(c->widthButton, avail);
	gtk_widget_set_sensitive(c->puncceButton, avail);
	if (model->tcscAvailable)
		gtk_widget_set_sensitive(c->tcscButton, avail);
#endif

	return c;
}

/* ------------------------------------------------------------------------- */
static void
status_controls_free(StatusControls *c)
{
        g_free(c);
        // FIXME: more to free here
}


/* ========================================================================= */
/* ==================== Model changes handlers ============================= */
/* ========================================================================= */
#if NEW_PROPERTY
#else
static void
controls_puncce_updated(gboolean is_cp)
{
        if (is_cp) {
        	gtk_label_set_text(GTK_LABEL(window->controls->puncceLabel), _("CP"));
			gtk_label_set_text(GTK_LABEL(window->controls_floating->puncceLabel), _("CP"));
		}else {
        	gtk_label_set_text(GTK_LABEL(window->controls->puncceLabel), _("EP"));
			gtk_label_set_text(GTK_LABEL(window->controls_floating->puncceLabel), _("EP"));
		}
}
#endif
/* ------------------------------------------------------------------------- */
#if NEW_PROPERTY
#else
static void
controls_fullwidth_updated(gboolean is_fullwidth)
{
	if (is_fullwidth) {
		gtk_label_set_text(GTK_LABEL(window->controls->widthLabel), _("FW"));
		gtk_label_set_text(GTK_LABEL(window->controls_floating->widthLabel), _("FW"));
	}else {
		gtk_label_set_text(GTK_LABEL(window->controls->widthLabel), _("HW"));
		gtk_label_set_text(GTK_LABEL(window->controls_floating->widthLabel), _("HW"));
	}
}
#endif
/* ------------------------------------------------------------------------- */
static void
controls_current_im_updated(IMInfo *im)
{
        gchar *name = _("English");

        if (im)
                name = _(im->cname);

        gtk_label_set_text(GTK_LABEL(window->controls->imLabel), name);
		gtk_label_set_text(GTK_LABEL(window->controls_floating->imLabel), name);
}

/* ------------------------------------------------------------------------- */
#if NEW_PROPERTY
#else
static void
controls_tcsc_mode_updated(UnihanTCSCMode tcsc)
{
	gchar *str;
	switch (tcsc) {
		case UNIHAN_TCSC_TO_SIMP: // 1
			str = _("->SC");
			break;
		case UNIHAN_TCSC_TO_TRAD: // 2
			str = _("->TC");
			break;
		default:
                        tcsc = UNIHAN_TCSC_NO_CONV;
			str = _("NoConv");
	}
	gtk_label_set_text(GTK_LABEL(window->controls->tcscLabel), str);
	gtk_label_set_text(GTK_LABEL(window->controls_floating->tcscLabel), str);
	if (tcsc == 0)
		no_tcsc_conv = TRUE;
	else
		no_tcsc_conv = FALSE;

	present_applet_window();

        stop_sending_tcsc = TRUE;
        GList *menu = gtk_container_get_children(GTK_CONTAINER(window->tcscMenu));
        GtkWidget *mi = (GtkWidget *)g_list_nth_data(menu, tcsc);
        if (!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(mi)))
                gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(mi), TRUE);
}
#endif
/* ------------------------------------------------------------------------- */
static void
controls_unihan_available(gboolean avail)
{
	gtk_widget_set_sensitive(window->controls->imButton, avail);
	gtk_widget_set_sensitive(window->controls->widthButton, avail);
	gtk_widget_set_sensitive(window->controls->puncceButton, avail);
	gtk_widget_set_sensitive(window->controls_floating->imButton, avail);
	gtk_widget_set_sensitive(window->controls_floating->widthButton, avail);
	gtk_widget_set_sensitive(window->controls_floating->puncceButton, avail);

    if (model->tcscAvailable) {
		gtk_widget_set_sensitive(window->controls->tcscButton, avail);
		gtk_widget_set_sensitive(window->controls_floating->tcscButton, avail);
	}
}

/* ------------------------------------------------------------------------- */
static void
receive_im_list(aux_ext_data_t *aux_ext_data)
{
	int im_count, i;

	im_count = aux_ext_data->string_count / 2;

	DEBUG_LOG("received IM list, im_count = %d", im_count);

	GConfClient *client = gconf_client_get_default();
	gboolean prepend_before = gconf_client_get_bool(client, PREFEDIT_IM_CURR_LIST_PREPEND_KEY, NULL);
	if (prepend_before) {
		IMInfo *info = (IMInfo *)(model->imCurrList->data);
		model->imCurrList = g_list_remove(model->imCurrList, info);
		gconf_client_set_bool(client, PREFEDIT_IM_CURR_LIST_PREPEND_KEY, False, NULL);
	}

	
	GList *im_list = NULL;
	GList *im_curr_list = NULL;
	for (i = 0; i < im_count; i++) {
		IMInfo *iminfo;
		iminfo = g_new0(IMInfo, 1);
		iminfo->id = g_strdup(aux_ext_data->string_list[i*2].ptr);
		iminfo->cname = g_strdup(_(aux_ext_data->string_list[i*2+1].ptr));
		im_list = g_list_append(im_list, iminfo);
	}

        /* create im_curr_list */
        im_curr_list = get_curr_list_by_im_all_list(im_list);
#if NEW_PROPERTY
	    imlist = im_curr_list;
	    DEBUG_LOG("get im_curr_list\n\r");
#endif  
	    status_model_im_list_set(model, im_list);
        status_model_im_curr_list_set(model, im_curr_list);

	return;
}

/* ------------------------------------------------------------------------- */
#if NEW_PROPERTY
#else
static void
receive_tcsc_mode(aux_ext_data_t *aux_ext_data)
{
	int tcsc = aux_ext_data->integer_list[1];
        status_model_tcsc_mode_set(model, tcsc);
}
#endif

#if TIMEBOMB
/* ------------------------------------------------------------------------- */
static void
demo_expired(void)
{
        expired = TRUE;

        // disable everything
        status_unihan_available_set(model, FALSE);

        // tell the user about this
        GtkWidget *dialog = gtk_dialog_new_with_buttons(_("Unihan 2 Expired"),
                        NULL,
                        GTK_DIALOG_NO_SEPARATOR,
                        GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE,
                        NULL);
        gtk_container_set_border_width(GTK_CONTAINER(dialog), 6);
        gtk_window_set_position(GTK_WINDOW(dialog), GTK_WIN_POS_CENTER);
        gtk_window_set_resizable(GTK_WINDOW(dialog), FALSE);
        gtk_window_set_destroy_with_parent(GTK_WINDOW(dialog), FALSE);

        GtkWidget *hbox = gtk_hbox_new(FALSE, 12);
        gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), hbox, TRUE, TRUE, 0);
        gtk_container_set_border_width(GTK_CONTAINER(hbox), 6);

        GtkWidget *icon = gtk_image_new_from_stock("gtk-dialog-error", GTK_ICON_SIZE_DIALOG);
        gtk_box_pack_start(GTK_BOX(hbox), icon, FALSE, FALSE, 0);
        gtk_misc_set_alignment(GTK_MISC(icon), 0, 0);

        GtkWidget *vbox = gtk_vbox_new(FALSE, 6);
        gtk_box_pack_start(GTK_BOX(hbox), vbox, FALSE, FALSE, 0);

        GtkWidget *label = gtk_label_new(_("<b>This demo version of Unihan 2 has expired.</b>\n\nChinese input is now disabled.\n\nPlease contact Sun Wah Linux for more information on Unihan 2."));
        gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);
        GTK_WIDGET_SET_FLAGS(label, GTK_CAN_FOCUS);
        gtk_label_set_use_markup(GTK_LABEL(label), TRUE);
        gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
        gtk_label_set_selectable(GTK_LABEL(label), TRUE);
        gtk_misc_set_alignment(GTK_MISC(label), 0, 0);

	GtkWidget *l = gtk_label_new(NULL);
	gtk_label_set_markup(GTK_LABEL(l), "<span foreground='blue' background='white' underline='single'>http://www.openrays.org/</span>");
        GtkWidget *button1 = gtk_event_box_new();
	gtk_container_add(GTK_CONTAINER(button1), l);
	g_signal_connect(button1, "button_press_event", G_CALLBACK(link_button_clicked_handler), NULL);
        gtk_box_pack_start(GTK_BOX(vbox), button1, FALSE, FALSE, 0);

        gtk_button_box_set_layout(GTK_BUTTON_BOX(GTK_DIALOG(dialog)->action_area), GTK_BUTTONBOX_END);

#if 0
        GtkWidget *button1 = gtk_button_new();
        gtk_dialog_add_action_widget(GTK_DIALOG(dialog), button1, GTK_RESPONSE_OK);
        GtkWidget *alignment1 = gtk_alignment_new(0.5, 0.5, 0, 0);
        gtk_container_add(GTK_CONTAINER(button1), alignment1);
        GtkWidget *hbox2 = gtk_hbox_new(FALSE, 2);
        gtk_container_add(GTK_CONTAINER(alignment1), hbox2);
        GtkWidget *image2 = gtk_image_new_from_stock("gtk-jump-to", GTK_ICON_SIZE_BUTTON);
        gtk_box_pack_start(GTK_BOX(hbox2), image2, FALSE, FALSE, 0);
        GtkWidget *label2 = gtk_label_new_with_mnemonic(_("Unihan _website"));
        gtk_box_pack_start(GTK_BOX(hbox2), label2, FALSE, FALSE, 0);
#endif

        g_signal_connect(G_OBJECT(dialog), "response", 
                         G_CALLBACK(gtk_widget_destroy), NULL);
        gtk_widget_show_all(dialog);
}
#endif

/* ------------------------------------------------------------------------- */
static void
present_applet_window(void)
{
	if (focus_lost_timer != 0) {
		g_source_remove(focus_lost_timer);
		focus_lost_timer = 0;
	}
	if (window->runAsApplet) {
		if (window->model->language == 1) {
			gtk_widget_show(window->controls->icon);
			gtk_widget_show(window->controls->widthButton);
			gtk_widget_show(window->controls->puncceButton);
			gtk_widget_show(window->controls->tcscButton);
			gtk_widget_show(window->controls->imButton);
			gtk_widget_set_sensitive(window->controls->imButton, window->model->unihanAvailable);
			gtk_widget_set_sensitive(window->controls->widthButton, window->model->unihanAvailable);
			gtk_widget_set_sensitive(window->controls->puncceButton, window->model->unihanAvailable);
		} else if (window->model->language ==2 ) {
			gtk_widget_hide(window->controls->widthButton);
			gtk_widget_hide(window->controls->puncceButton);
			gtk_widget_hide(window->controls->tcscButton);
			gtk_widget_show(window->controls->imButton);
			gtk_widget_show(window->controls->icon);
			gtk_widget_set_sensitive(window->controls->imButton, window->model->unihanAvailable);
		} else {
			gtk_widget_hide(window->controls->widthButton);
			gtk_widget_hide(window->controls->puncceButton);
			gtk_widget_hide(window->controls->tcscButton);
			gtk_widget_hide(window->controls->imButton);
			gtk_widget_show(window->controls->icon);
		}
		if (no_tcsc_conv)
			gtk_widget_hide(window->controls->tcscButton);
	} else {
		if (window->model->language==1) {
			gtk_widget_set_sensitive(window->controls_floating->imButton, window->model->unihanAvailable);
			gtk_widget_set_sensitive(window->controls_floating->widthButton, window->model->unihanAvailable);
			gtk_widget_set_sensitive(window->controls_floating->puncceButton, window->model->unihanAvailable);
			if (no_tcsc_conv) {
				gtk_widget_hide(window->controls_floating->tcscButton);
			} else {
				gtk_widget_show(window->controls_floating->tcscButton);
				gtk_widget_set_sensitive(window->controls_floating->tcscButton, window->model->unihanAvailable);
			}
		}else {
			gtk_widget_set_sensitive(window->controls_floating->imButton, window->model->unihanAvailable);
			gtk_widget_set_sensitive(window->controls_floating->widthButton, FALSE);
			gtk_widget_set_sensitive(window->controls_floating->puncceButton, FALSE);
			gtk_widget_hide(window->controls_floating->tcscButton);
		}
	}
}

/* ------------------------------------------------------------------------- */
static gboolean
lost_focus_timeout(gpointer data)
{
	if (!window->runAsApplet && !focused && !window->doNotHide) {
		gtk_widget_hide(window->appletWindow);
        }
	gtk_widget_set_sensitive(window->controls->imButton, FALSE);
	gtk_widget_set_sensitive(window->controls->widthButton, FALSE);
	gtk_widget_set_sensitive(window->controls->puncceButton, FALSE);
	gtk_widget_set_sensitive(window->controls_floating->imButton, FALSE);
	gtk_widget_set_sensitive(window->controls_floating->widthButton, FALSE);
	gtk_widget_set_sensitive(window->controls_floating->puncceButton, FALSE);

        focus_lost_timer = 0;
	return FALSE;
}

/* ------------------------------------------------------------------------- */
static gboolean
applet_menu_enter_notify_event_handler(GtkWidget *widget, GdkEventCrossing *event, gpointer user_data)
{
	window->doNotHide = TRUE;
	return FALSE;
}

/* ------------------------------------------------------------------------- */
static gboolean
applet_menu_leave_notify_event_handler(GtkWidget *widget, GdkEventCrossing *event, gpointer user_data)
{
	window->doNotHide = FALSE;
	return FALSE;
}

/* ------------------------------------------------------------------------- */
#if NEW_PROPERTY
#else
static void
applet_tcsc_button_pressed_event_handler(GtkButton *button, gpointer user_data)
{
	window->doNotHide = TRUE;
}


/* ------------------------------------------------------------------------- */
static void
applet_tcsc_menu_deactivate_event_handler(GtkMenuShell *menushell, gpointer user_data)
{
	window->doNotHide = FALSE;
}
#endif
/** ------------------------------------------------------------------------- */
static void
show_about_box(void)
{
	GtkWidget *about;
	GtkWidget *hbox, *vbox, *label;
	
	gtk_rc_parse_string("style 'unihan-about-box-style'\n"
			    "{\n"
			    "bg[NORMAL] = 'white'\n"
			    "bg_pixmap[NORMAL] = '<none>'\n"
			    "}\n"
			    "widget 'unihan-about-box' style 'unihan-about-box-style'");

	about = gtk_dialog_new_with_buttons(_("About Unihan"),
					    NULL,
					    GTK_DIALOG_NO_SEPARATOR,
					    GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE,
					    NULL);
	gtk_widget_set_name(about, "unihan-about-box");
        gtk_container_set_border_width(GTK_CONTAINER(about), 6);
	
#if NEW_PROPERTY
	hbox = gtk_hbox_new(FALSE, 10);
#else
	hbox = gtk_hbox_new(FALSE, 7 );
#endif
	gtk_container_set_border_width(GTK_CONTAINER(hbox), 7);
#if NEW_PROPERTY
	vbox=gtk_vbox_new(FALSE, 0);
#else
	vbox=gtk_vbox_new(FALSE, 0);
#endif
	gtk_container_set_border_width(GTK_CONTAINER(vbox),7);	
	gtk_box_pack_start(GTK_BOX(hbox), vbox,TRUE,TRUE,1);
	label = gtk_label_new(NULL);
	gtk_label_set_markup(GTK_LABEL(label), _("Unihan Chinese input system"));
	gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 2);
	label = gtk_label_new(NULL);
	gtk_label_set_markup(GTK_LABEL(label), g_strdup_printf(_("version %s"), VERSION));
	gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);
	label = gtk_image_new_from_file(UNIHAN_DATA_DIR "/images/logo.jpg");
	gtk_box_pack_start_defaults(GTK_BOX(vbox), label);
#if TIMEBOMB
        if (expire_date != 0) {
                char date[2048];
                struct tm datetime;
                gmtime_r(&expire_date, &datetime);
                memset(date, 0, 2048);
                strftime(date, 2047, _("This demo expires on %A, %d %B %Y."), &datetime);
                label = gtk_label_new(NULL);
                gtk_label_set_markup(GTK_LABEL(label), date);
                gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
                gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
		gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);
        }
#endif
	label = gtk_label_new(NULL);
	gtk_label_set_markup(GTK_LABEL(label), _("Copyright © 2002-2007 Sun Wah Linux Ltd.\n\nPortions Copyright © Sun Microsystems, Inc.\n\nZhineng ABC 6.0 Input Method invented and designed by Zhu Shoutao, Beijing University.\n\nUnispim 3.0 Input Method invented and designed by Unispim co.ltd."));
        gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
	gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);

	GtkWidget *l = gtk_label_new(NULL);
	gtk_label_set_markup(GTK_LABEL(l), "<span foreground='blue' background='white' underline='single'>http://www.openrays.org/</span>");
	label = gtk_event_box_new();
	gtk_container_add(GTK_CONTAINER(label), l);
	g_signal_connect(label, "button_press_event", G_CALLBACK(link_button_clicked_handler), NULL);
	gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);

	gtk_box_pack_start_defaults(GTK_BOX(GTK_DIALOG(about)->vbox),hbox);

	g_signal_connect(G_OBJECT(about), "response", G_CALLBACK(gtk_widget_destroy), NULL);
	gtk_dialog_set_default_response(GTK_DIALOG(about), GTK_RESPONSE_CLOSE);
	gtk_widget_show_all(GTK_WIDGET(about));
}
/* ------------------------------------------------------------------------- */
#if NEW_PROPERTY
static gint
icon_im_press_handler(GtkWidget *w, GdkEventButton *e, gpointer data)
{
	if (e->type != GDK_BUTTON_PRESS)
		return FALSE;
	
	if (e->button == 3)
	{
		gtk_menu_popup(GTK_MENU(window->mainMenu), NULL, NULL, 
			       menu_position_func, w,
			       e->button, e->time);
		return TRUE;
	}
	//else
	if (e->button == 1)
	{
		//if (english_im_flag == 0)
		//{
		 DEBUG_LOG("the button is 1\n\r");
		 GSList 		*menugrp = NULL;
	     GtkWidget 	*eng_item;
		 if (!window->imMenu) 
		 {
		 window->imMenu = gtk_menu_new();

		 g_signal_connect(G_OBJECT(window->imMenu), "enter-notify-event",
				 G_CALLBACK(applet_menu_enter_notify_event_handler), NULL);
		 g_signal_connect(G_OBJECT(window->imMenu), "leave-notify-event",
				 G_CALLBACK(applet_menu_leave_notify_event_handler), NULL);

		 gtk_menu_prepend(GTK_MENU(window->imMenu), create_menu_separator());

#ifdef WITH_HWPENX
		 if (is_hwpenx_available()) 
		 {
		    hwpenx_set_start_failed_handler(hwpenx_start_failed);
		    hwpenx_set_exited_handler(hwpenx_exited);
		    // put hwpenx on the menu
		    hwpenx_item = gtk_check_menu_item_new_with_label(_("Hanwang Handwriting"));
		    g_signal_connect(G_OBJECT(hwpenx_item), "toggled",
			    G_CALLBACK(hwpenx_item_handler), NULL);
		    gtk_widget_show(hwpenx_item);
		    gtk_menu_prepend(GTK_MENU(window->imMenu), hwpenx_item);
		    gtk_menu_prepend(GTK_MENU(window->imMenu), create_menu_separator());
		  }
#endif

#if WTPEN
		 if (is_wtpen_available()) 
		 {
			wtpen_set_start_failed_handler(wtpen_start_failed);
			wtpen_set_exited_handler(wtpen_exited);

			wtpen_item = gtk_check_menu_item_new_with_label(_("Wintone Handwriting"));
			g_signal_connect(G_OBJECT(wtpen_item), "toggled",
				G_CALLBACK(wtpen_item_handler), NULL);
			gtk_widget_show(wtpen_item);
			gtk_menu_prepend(GTK_MENU(window->imMenu), wtpen_item);
			gtk_menu_prepend(GTK_MENU(window->imMenu), create_menu_separator());
		  }
#endif

		  eng_item = gtk_radio_menu_item_new_with_label(menugrp, _("English"));
		  menugrp = gtk_radio_menu_item_get_group(GTK_RADIO_MENU_ITEM(eng_item));
		  if (!window->model->currIM) 
		  {
			 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(eng_item), TRUE);
		  }
		  g_signal_connect(G_OBJECT(eng_item), "activate",
				 G_CALLBACK(conversion_off_handler), NULL);
		  gtk_widget_show(eng_item);
		  gtk_menu_prepend(GTK_MENU(window->imMenu), eng_item);
        
          GList *im_list_ = window->model->imCurrList;
		  while (im_list_) 
		  {
			  IMInfo *im = (IMInfo *)im_list_->data;
			  GtkWidget *item;

			  item = gtk_radio_menu_item_new_with_label(menugrp, im->cname);
			  menugrp = gtk_radio_menu_item_get_group(GTK_RADIO_MENU_ITEM(item));
			  if (im == window->model->currIM) 
			  {
				  gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item), TRUE);
			  }
			  g_signal_connect(G_OBJECT(item), "activate",
					      G_CALLBACK(switch_im_handler), im);
	
			  gtk_widget_show_all(item);
			  gtk_menu_append(GTK_MENU(window->imMenu), item);
			  im_list_ = im_list_->next;
		   }

		   gtk_menu_append(GTK_MENU(window->imMenu), create_menu_separator());
		   /* virtual punc keyboard */
		   punc_kbd_item = gtk_check_menu_item_new_with_label(_("Punc Keyboard"));
		   punc_kbd_item_handler_id = g_signal_connect(G_OBJECT(punc_kbd_item),
				         "toggled", G_CALLBACK(punc_kbd_item_handler), NULL);
		   gtk_widget_show(punc_kbd_item);
		   gtk_menu_append(GTK_MENU(window->imMenu), punc_kbd_item);
		   /* virtual US keyboard */
		   us_kbd_item = gtk_check_menu_item_new_with_label(_("US Keyboard"));
		   us_kbd_item_handler_id = g_signal_connect(G_OBJECT(us_kbd_item),
				       "toggled", G_CALLBACK(us_kbd_item_handler), NULL);
		   gtk_widget_show(us_kbd_item);
		   gtk_menu_append(GTK_MENU(window->imMenu), us_kbd_item);


		   gtk_widget_show_all(window->imMenu);
		   g_object_ref(window->imMenu);

	      } 
		  else 
		  {
		// update the IM menu
		      GList *items = GTK_MENU_SHELL(window->imMenu)->children;
		
		      im_menu_ignore_activate = TRUE;
#ifdef WITH_HWPENX
		      hwpenxIgnoreToggle = TRUE;
#endif

#if WTPEN
		      wtpenIgnoreToggle = TRUE;
#endif

		      for (; items; items = g_list_next(items)) 
			 {
			      GtkWidget *itemLabel = gtk_bin_get_child(GTK_BIN(items->data));
			      const char *itemName = NULL;
			      if (!itemLabel || !GTK_IS_LABEL(itemLabel))
				  continue;
			      itemName = gtk_label_get_text(GTK_LABEL(itemLabel));
			      if (window->model->currIM && itemName && !strcmp(window->model->currIM->cname, itemName)) 
			      {
				      gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(items->data), TRUE);
			      }
			      else if (!window->model->currIM) {
				      gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(items->data),
						TRUE);
				      break;
			      }
		      }

#ifdef WITH_HWPENX
		      hwpenxIgnoreToggle = FALSE;
#endif

#if WTPEN
		      wtpenIgnoreToggle = FALSE;
#endif
		      im_menu_ignore_activate = FALSE;
	      }
	   gtk_menu_popup(GTK_MENU(window->imMenu), NULL, NULL, 
			       menu_position_func, w,
			       e->button, e->time);
	   return TRUE;
	  }
	  /*else
	  {
		gtk_menu_popup(GTK_MENU(window->mainMenu), NULL, NULL, 
			       menu_position_func, w,
			       e->button, e->time); 
	  }*/
	//}
	//if (e->type != GDK_BUTTON_PRESS)
		//return FALSE;
	
	
return FALSE;
}
#endif
static gint
icon_press_handler(GtkWidget *w, GdkEventButton *e, gpointer data)
{
	if (unset_focus_before) {
		present_applet_window();
		click_status=1;
		unset_focus_before=0;
	}else {
		click_status=1;
	}

	if (e->type != GDK_BUTTON_PRESS)
		return FALSE;

	if (e->button == 3) {
		gtk_menu_popup(GTK_MENU(window->mainMenu), NULL, NULL,
					menu_position_func, w,
					e->button, e->time);
		return TRUE;
	}
	
	if (e->button == 1 && window->runAsApplet == TRUE) {
		create_im_menu();
		gtk_menu_popup(GTK_MENU(window->imMenu), NULL, NULL, 
			       menu_position_func, w,
			       e->button, e->time);
		return TRUE;
	}

	if (e->button == 1 && window->runAsApplet == FALSE) {
		if (timer_for_moving)
			gtk_timeout_remove(timer_for_moving);
		if (timer_for_clean)
			gtk_timeout_remove(timer_for_clean);
		timer_for_moving = gtk_timeout_add(10, write_coordinates, NULL); 
		timer_for_clean = gtk_timeout_add(3000, clean_timer_for_moving, NULL);
		gtk_window_begin_move_drag(GTK_WINDOW(window->appletWindow), 
                                           e->button, 
				           e->x_root, e->y_root, e->time);
		return TRUE;
	}

	return FALSE;
}
/* ------------------------------------------------------------------------- */
static gint
pref_item_handler(GtkMenuItem *mi, gpointer data)
{
	int pid;
	char *const argv[2] = { BINDIR "/unihan2-prefs", NULL };

	gboolean started = gdk_spawn_on_screen(gdk_screen_get_default(), 
	                                       NULL, 
					       argv, NULL, 
					       0, 
					       NULL, NULL, 
					       &pid, 
					       NULL);
	DEBUG_LOG("starting unihan2-prefs, pid = %d", pid);
	if (!started) {
		GtkWidget *dialog = gtk_message_dialog_new(NULL, 0, 
				GTK_MESSAGE_ERROR,
				GTK_BUTTONS_CLOSE,
				_("Could not start the Unihan Preferences utility."));
		g_signal_connect(G_OBJECT(dialog), "response",
				G_CALLBACK(gtk_widget_destroy), NULL);
		gtk_widget_show_all(dialog);
	}
	return TRUE;
}

/* ------------------------------------------------------------------------- */
static gint 
about_item_handler(GtkMenuItem *mi, gpointer data)
{
	show_about_box();
	return TRUE;
}

#define UNIHAN_STATUS_HIDE_ICON		1
#define UNIHAN_STATUS_ABOUT_ITEM	2
#define UNIHAN_STATUS_PREFERENCES_ITEM	3

/* ------------------------------------------------------------------------- */
static gboolean 
plug_client_msg_handler(GtkWidget *w, GdkEventClient *e, gpointer data)
{
	char *atom = gdk_atom_name(e->message_type);
	gboolean isUIControl = !strcmp("_UNIHAN_STATUS_UI_CONTROL", atom);

	g_free(atom);
	if (!isUIControl)
		return FALSE;

	switch (e->data.l[0]) {
		case UNIHAN_STATUS_HIDE_ICON:
			gtk_widget_hide(window->controls->icon);
			break;
		case UNIHAN_STATUS_PREFERENCES_ITEM:
			pref_item_handler(NULL, NULL);
			break;
		case UNIHAN_STATUS_ABOUT_ITEM:
			about_item_handler(NULL, NULL);
			break;
	}

	return TRUE;
}

/* ------------------------------------------------------------------------- */
static void
recreate_controls(void)
{
	// plug was destroyed!
	// need to recreate plugs and controls
    g_free(window->controls);
    window->controls = status_controls_new(window);
	plug = create_plug();
	already_plugged = FALSE;
	find_system_tray();
	present_applet_window();
}

/* ------------------------------------------------------------------------- */
static gboolean
plug_destroyed_oops_handler(GtkWidget *w, GdkEvent *e, gpointer data)
{
	// The GdkWindow got destroyed, but the GtkWidget is not.
	// We need to explicitly destroy the GtkWidget too.
	// Perhaps the socket crashed?
	gtk_widget_destroy(w);
	return TRUE;
}

/* ------------------------------------------------------------------------- */
static gboolean
plug_destroy_handler(GtkObject *o, gpointer data)
{
	// If the socket is removed from the panel through "normal"
	// means, the plug will be destroyed properly, and reach here.
	recreate_controls();
	return TRUE;
}

/* ------------------------------------------------------------------------- */
static GtkWidget *
create_plug(void)
{
	GtkWidget *newplug = gtk_plug_new(0);
	g_signal_connect(G_OBJECT(newplug), "embedded",
			 G_CALLBACK(plug_embedded_handler), NULL);
	g_signal_connect(G_OBJECT(newplug), "destroy-event",
			 G_CALLBACK(plug_destroyed_oops_handler), NULL);
	g_signal_connect(G_OBJECT(newplug), "destroy",
			 G_CALLBACK(plug_destroy_handler), NULL);
	g_signal_connect(G_OBJECT(newplug), "client-event",
			 G_CALLBACK(plug_client_msg_handler), NULL);
	return newplug;
}

/* ------------------------------------------------------------------------- */
static void
find_system_tray(void)
{
	char *systray_atom_name = NULL;
	Atom systray_atom = None;
	Window systray = None;
	Display *dpy = GDK_DISPLAY();
	Screen *xscreen = DefaultScreenOfDisplay(dpy);
	Window rootwin = None;
	XSetWindowAttributes xswa;

	// atom for the current screen
	systray_atom_name = g_strdup_printf("_NET_SYSTEM_TRAY_S%d", XScreenNumberOfScreen(xscreen));
	systray_atom = XInternAtom(dpy, systray_atom_name, True);
	g_free(systray_atom_name);
	if (systray_atom != None) {
		// attempt to get the system tray window
		gdk_error_trap_push();
		systray = XGetSelectionOwner(dpy, systray_atom);
		XSync(dpy, False);
		if ((gdk_error_trap_pop() == 0) && (systray != None))
			dock_plug_to_system_tray(plug, systray);
	}

	// if systray starts afterwards, we want to know that too
	memset(&xswa, 0, sizeof(xswa));
	xswa.event_mask = StructureNotifyMask;
	rootwin = RootWindow(dpy, XScreenNumberOfScreen(xscreen));
	XChangeWindowAttributes(dpy, rootwin, CWEventMask, &xswa);
	gdk_add_client_message_filter(gdk_atom_intern("MANAGER", FALSE), manager_filter, NULL);
}

/* ------------------------------------------------------------------------- */
static GdkFilterReturn
manager_filter(GdkXEvent *xev, GdkEvent *gdkev, gpointer data)
{
	XEvent *ev = (XEvent *)xev;
	Display *dpy = GDK_DISPLAY();
	Screen *xscreen = DefaultScreenOfDisplay(dpy);
	Window rootwin = RootWindow(dpy, XScreenNumberOfScreen(xscreen));
	char *systray_atom_name = NULL;
	char *ev_atom_name = NULL;
	int strcmp_r;

	if (ev->xany.window != rootwin)
		return GDK_FILTER_CONTINUE;

	systray_atom_name = g_strdup_printf("_NET_SYSTEM_TRAY_S%d", XScreenNumberOfScreen(xscreen));
	ev_atom_name = XGetAtomName(dpy, (Atom)ev->xclient.data.l[1]);
	strcmp_r = strcmp(systray_atom_name, ev_atom_name);
	g_free(systray_atom_name);
	XFree(ev_atom_name);
	// is this the systray announcement?
	if (strcmp_r != 0)
		return GDK_FILTER_CONTINUE;

	dock_plug_to_system_tray(plug, (Window)ev->xclient.data.l[2]);
	return GDK_FILTER_REMOVE;
}

/* ------------------------------------------------------------------------- */
static void
dock_plug_to_system_tray(GtkWidget *p, Window systray)
{
	XEvent ev;
	Display *dpy = GDK_DISPLAY();

	memset(&ev, 0, sizeof(ev));
	ev.xclient.type = ClientMessage;
	ev.xclient.window = systray;
	ev.xclient.message_type = XInternAtom(dpy, "_NET_SYSTEM_TRAY_OPCODE", False);
	ev.xclient.format = 32;
	ev.xclient.data.l[0] = CurrentTime;
	ev.xclient.data.l[1] = 0; // SYSTEM_TRAY_REQUEST_DOCK == 0
	ev.xclient.data.l[2] = gtk_plug_get_id(GTK_PLUG(p));

	gdk_error_trap_push();
	XSendEvent(dpy, systray, False, NoEventMask, &ev);
	XSync(dpy, False);
	gdk_error_trap_pop();	// silently ignore errors
}


/* ------------------------------------------------------------------------- */

/* ------------------------------------------------------------------------- */
static StatusWindow *
status_window_new(StatusModel *m)
{
        StatusWindow *w = g_new0(StatusWindow, 1);
        w->model = m;

        w->runAsApplet = FALSE;
        w->appletWindow = gtk_window_new(GTK_WINDOW_POPUP);
	gtk_window_set_wmclass(GTK_WINDOW(w->appletWindow), "unihan", "StatusAux");
	gtk_window_set_title(GTK_WINDOW(w->appletWindow), "Unihan");
	gtk_window_set_resizable(GTK_WINDOW(w->appletWindow), FALSE);
	gtk_window_set_decorated(GTK_WINDOW(w->appletWindow), FALSE);
	gtk_window_stick(GTK_WINDOW(w->appletWindow));
	gtk_window_set_gravity(GTK_WINDOW(w->appletWindow), GDK_GRAVITY_SOUTH_WEST);
	gtk_window_set_accept_focus(GTK_WINDOW(w->appletWindow), FALSE);
	gtk_window_move(GTK_WINDOW(w->appletWindow), 0,
			(gdk_screen_height() > 64 ? gdk_screen_height() - 64 : 0));
	g_signal_connect(G_OBJECT(w->appletWindow), "delete-event",
			 G_CALLBACK(gtk_true), NULL);
 
	w->appletFrame = gtk_frame_new(NULL);
	gtk_frame_set_shadow_type(GTK_FRAME(w->appletFrame), GTK_SHADOW_OUT);
	g_object_set(G_OBJECT(w->appletFrame), "can-focus", False, NULL);
	gtk_container_add(GTK_CONTAINER(w->appletWindow), w->appletFrame);

	w->controls = status_controls_new(w);

	w->controls_floating = status_controls_new(w);
	gtk_container_add(GTK_CONTAINER(w->appletFrame), w->controls_floating->hbox);
	gtk_widget_show_all(GTK_WIDGET(w->appletWindow));

	w->mainMenu = create_main_menu();
	//w->imMenu = create_im_menu();

       if (m->tcscAvailable)
               w->tcscMenu = create_tcsc_menu();
        
        return w;
}


/* ------------------------------------------------------------------------- */
static void
status_window_free(StatusWindow *w)
{
        status_controls_free(w->controls);
		status_controls_free(w->controls_floating);
        g_free(w);
        // FIXME: lots more to free here
}




/* ------------------------------------------------------------------------- */
static void
conversion_off_handler(GtkMenuItem *w, gpointer data)
{
	int int_values[1];

	if (im_menu_ignore_activate)
		return;

	if (!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w)))
		return;

	int_values[0] = UNIHAN_ENGINE_CONV_OFF;
	send_to_engine(1, int_values, 0, NULL);
}

/* ------------------------------------------------------------------------- */
static void
switch_im_handler(GtkMenuItem *w, gpointer data)
{
	int int_values[1];
	char *string_values[1];
	IMInfo *inf = (IMInfo *)data;

	if (im_menu_ignore_activate)
		return;

	//if (!w->active) return;
	if (!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w)))
		return;

	DEBUG_LOG("switching im to %s", inf->id);

	int_values[0] = UNIHAN_ENGINE_SWITCH_IM;
	string_values[0] = inf->id;
	send_to_engine(1, int_values, 1, string_values);
}

/* ------------------------------------------------------------------------- */
#if NEW_PROPERTY
#else
static void
toggle_puncce_handler(GtkMenuItem *w, gpointer data)
{
	if (unset_focus_before) {
		present_applet_window();
		click_status=1;
		unset_focus_before=0;
	}else {
		click_status=1;
	}

	int int_values[1];

	int_values[0] = UNIHAN_ENGINE_TOGGLE_PUNCCE;
	send_to_engine(1, int_values, 0, NULL);
}

/* ------------------------------------------------------------------------- */
static void
toggle_width_handler(GtkMenuItem *w, gpointer data)
{
	if (unset_focus_before) {
		present_applet_window();
		click_status=1;
		unset_focus_before=0;
	}else {
		click_status=1;
	}

	int int_values[1];

	int_values[0] = UNIHAN_ENGINE_TOGGLE_WIDTH;
	send_to_engine(1, int_values, 0, NULL);
	DEBUG_LOG("send UNIHAN_ENGINE_TOGGLE_WIDTH to le\n");
}

/* ------------------------------------------------------------------------- */
static void
tcsc_item_handler(GtkMenuItem *w, gpointer data)
{
	int tcsc = GPOINTER_TO_INT(data);
	int int_values[2] = { UNIHAN_ENGINE_SET_TCSC_MODE, tcsc };

	DEBUG_LOG("tcsc_item_handler, %d", tcsc);
	if (stop_sending_tcsc) {
		stop_sending_tcsc = FALSE;
		DEBUG_LOG("stop_sending_tcsc to FALSE");
		return;
	}
	GConfClient *client = gconf_client_get_default();       
	gconf_client_set_int(client, TC_SC_KEY, tcsc, NULL); 
}
#endif
/* ------------------------------------------------------------------------- */
static GtkWidget *
create_menu_separator(void)
{
	GtkWidget *item;

	item = gtk_menu_item_new();
	gtk_widget_set_sensitive(item, FALSE);
	gtk_widget_show(item);

	return item;
}


/* ------------------------------------------------------------------------- */
#if NEW_PROPERTY
#else
void create_im_menu()
{

	//FIXME:enable menu_click_renew
	/*
	int int_values[1];
	int_values[0] = UNIHAN_ENGINE_CHECK_MODULE_INFO;
	send_to_engine(1, int_values, 0, NULL);
	*/

	GSList 		*menugrp = NULL;
	GtkWidget 	*eng_item;
	//const gchar 	*curr_im_name = gtk_label_get_text(GTK_LABEL(im_label));

	if (window->imMenu) {
		gtk_widget_destroy(window->imMenu);
		window->imMenu = NULL;
	}
		window->imMenu = gtk_menu_new();

		g_signal_connect(G_OBJECT(window->imMenu), "enter-notify-event",
				 G_CALLBACK(applet_menu_enter_notify_event_handler), NULL);
		g_signal_connect(G_OBJECT(window->imMenu), "leave-notify-event",
				 G_CALLBACK(applet_menu_leave_notify_event_handler), NULL);

		gtk_menu_prepend(GTK_MENU(window->imMenu), create_menu_separator());

#ifdef WITH_HWPENX
		if (is_hwpenx_available()) {
		    hwpenx_set_start_failed_handler(hwpenx_start_failed);
		    hwpenx_set_exited_handler(hwpenx_exited);
		    // put hwpenx on the menu
		    hwpenx_item = gtk_check_menu_item_new_with_label(_("Hanwang Handwriting"));
		    g_signal_connect(G_OBJECT(hwpenx_item), "toggled",
			    G_CALLBACK(hwpenx_item_handler), NULL);
		    gtk_widget_show(hwpenx_item);
		    gtk_menu_prepend(GTK_MENU(window->imMenu), hwpenx_item);
		    gtk_menu_prepend(GTK_MENU(window->imMenu), create_menu_separator());
		}
#endif

#if WTPEN
		if (is_wtpen_available()) {
			wtpen_set_start_failed_handler(wtpen_start_failed);
			wtpen_set_exited_handler(wtpen_exited);

			wtpen_item = gtk_check_menu_item_new_with_label(_("Wintone Handwriting"));
			g_signal_connect(G_OBJECT(wtpen_item), "toggled",
				G_CALLBACK(wtpen_item_handler), NULL);
			gtk_widget_show(wtpen_item);
			gtk_menu_prepend(GTK_MENU(window->imMenu), wtpen_item);
			gtk_menu_prepend(GTK_MENU(window->imMenu), create_menu_separator());
		}
#endif

		eng_item = gtk_radio_menu_item_new_with_label(menugrp, _("English"));
		menugrp = gtk_radio_menu_item_get_group(GTK_RADIO_MENU_ITEM(eng_item));
		if (!window->model->currIM) {
			gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(eng_item), TRUE);
		}
		g_signal_connect(G_OBJECT(eng_item), "activate",
				 G_CALLBACK(conversion_off_handler), NULL);
		gtk_widget_show(eng_item);
		gtk_menu_prepend(GTK_MENU(window->imMenu), eng_item);

                GList *im_list_ = window->model->imCurrList;
		while (im_list_) {
			IMInfo *im = (IMInfo *)im_list_->data;
			GtkWidget *item;

			item = gtk_radio_menu_item_new_with_label(menugrp, im->cname);
			menugrp = gtk_radio_menu_item_get_group(GTK_RADIO_MENU_ITEM(item));
			if ( window->model->currIM && !strcmp(im->cname, window->model->currIM->cname) ) {
				gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item), TRUE);
			}
			g_signal_connect(G_OBJECT(item), "activate",
					 G_CALLBACK(switch_im_handler), im);
	
			gtk_widget_show_all(item);
			gtk_menu_append(GTK_MENU(window->imMenu), item);
			im_list_ = im_list_->next;
		}

		gtk_menu_append(GTK_MENU(window->imMenu), create_menu_separator());

		/* virtual punc keyboard */
		punc_kbd_item = gtk_check_menu_item_new_with_label(_("Punc Keyboard"));
		punc_kbd_item_handler_id = g_signal_connect(G_OBJECT(punc_kbd_item),
				"toggled", G_CALLBACK(punc_kbd_item_handler), NULL);
		gtk_widget_show(punc_kbd_item);
		gtk_menu_append(GTK_MENU(window->imMenu), punc_kbd_item);
		/* virtual US keyboard */
		us_kbd_item = gtk_check_menu_item_new_with_label(_("US Keyboard"));
		us_kbd_item_handler_id = g_signal_connect(G_OBJECT(us_kbd_item),
				"toggled", G_CALLBACK(us_kbd_item_handler), NULL);
		gtk_widget_show(us_kbd_item);
		gtk_menu_append(GTK_MENU(window->imMenu), us_kbd_item);

		gtk_widget_show_all(window->imMenu);
		g_object_ref(window->imMenu);

		// update the IM menu
		GList *items = GTK_MENU_SHELL(window->imMenu)->children;
		
		im_menu_ignore_activate = TRUE;
#ifdef WITH_HWPENX
		hwpenxIgnoreToggle = TRUE;
#endif

#if WTPEN
		wtpenIgnoreToggle = TRUE;
#endif

		for (; items; items = g_list_next(items)) {
			GtkWidget *itemLabel = gtk_bin_get_child(GTK_BIN(items->data));
			const char *itemName = NULL;
			if (!itemLabel || !GTK_IS_LABEL(itemLabel))
				continue;
			itemName = gtk_label_get_text(GTK_LABEL(itemLabel));
			if (window->model->currIM && itemName && !strcmp(window->model->currIM->cname, itemName)) {
				gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(items->data), TRUE);
			}
			else if (!window->model->currIM) {
				gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(items->data),
						TRUE);
				break;
			}
		}

#ifdef WITH_HWPENX
		hwpenxIgnoreToggle = FALSE;
#endif

#if WTPEN
		wtpenIgnoreToggle = FALSE;
#endif
		im_menu_ignore_activate = FALSE;
}

static void popup_im_menu_from_im_button(GtkWidget *w, gpointer data)
{
	if (unset_focus_before) {
		present_applet_window();
		click_status=1;
		unset_focus_before=0;
	}else {
		click_status=1;
	}

	create_im_menu();
	gtk_menu_popup(GTK_MENU(window->imMenu), NULL, NULL, 
		       menu_position_func, w, 1, GDK_CURRENT_TIME);
}
#endif

/* ------------------------------------------------------------------------- */
#if NEW_PROPERTY
#else
static void
tcsc_item_activate(GtkWidget *w, gpointer data)
{
	if (unset_focus_before) {
		present_applet_window();
		click_status=1;
		unset_focus_before=0;
	}else {
		click_status=1;
	}
	
	gtk_widget_show_all(window->tcscMenu);
	gtk_menu_popup(GTK_MENU(window->tcscMenu), NULL, NULL, 
		       menu_position_func, w, 1, GDK_CURRENT_TIME);
}
#endif
/* ------------------------------------------------------------------------- */
static void
plug_embedded_handler(GtkPlug *w, gpointer data)
{
	// already plugged into something else?
	if (already_plugged == TRUE) {
		return;
	}
	gtk_container_add(GTK_CONTAINER(w), GTK_WIDGET(window->controls->hbox));
	gtk_widget_show_all(GTK_WIDGET(w));
	already_plugged = TRUE;
	GConfClient *client = gconf_client_get_default();
	gboolean in_tray = gconf_client_get_bool(client, STATUS_IN_TRAY_KEY, NULL);
	if (in_tray) {
		window->runAsApplet = TRUE;
		gtk_widget_hide_all(window->appletWindow);
		gtk_widget_show_all(window->controls->hbox);
	}else {
		window->runAsApplet = FALSE;
		gtk_widget_hide_all(window->controls->hbox);
		gdk_window_raise(window->appletWindow->window);
		gtk_widget_show_all(window->appletWindow);
		hack_NET_SUPPORTED();
		gint x_coordinate = gconf_client_get_int(client, "/apps/sw-unihan/gnome_aux/status/x_coordinate", NULL);
		gint y_coordinate = gconf_client_get_int(client, "/apps/sw-unihan/gnome_aux/status/y_coordinate", NULL);
		gtk_window_move(GTK_WINDOW(window->appletWindow), x_coordinate, y_coordinate);
	}
	present_applet_window();
}

/* ------------------------------------------------------------------------- */
static void
clipboard_get_handler(GtkClipboard *cb, GtkSelectionData *sel_data, guint info, gpointer data)
{
	gchar *target = gdk_atom_name(sel_data->target);
	
	DEBUG_LOG("someone getting clipboard! target = %s", target);

	switch (info) {
                case TARGET_CLIENT_WINDOW: {
                        GdkNativeWindow window_id;
                        guchar *window_id_mem;

                        window_id = GDK_WINDOW_XWINDOW(GDK_WINDOW(window->appletWindow));
                        window_id_mem = (guchar *)&window_id;
                        gtk_selection_data_set(sel_data, GDK_SELECTION_TYPE_WINDOW,
                                               32, window_id_mem, 4);
                }
		break;
	
                case TARGET_PLUG_ID: {
                        GdkNativeWindow plug_id;
                        guchar *plug_id_mem;

                        plug_id = gtk_plug_get_id(GTK_PLUG(plug));
                        plug_id_mem = (guchar *)&plug_id;
                        gtk_selection_data_set(sel_data, GDK_SELECTION_TYPE_WINDOW,
                                               32, plug_id_mem, 4);
                }
		break;

                case TARGET_ALL_IM_LIST:
                case TARGET_CURR_IM_LIST: {
                        GList *im_list_ = (info == TARGET_ALL_IM_LIST) ? model->imList : model->imCurrList;
                        guint num_im = g_list_length(im_list_);
                        gchar **str_list = NULL;
                        gchar *final_str = NULL;
                        int i;

                        str_list = g_new0(gchar*, num_im * 2 + 2);
                        for (i = 0; im_list_; i++, im_list_ = g_list_next(im_list_)) {
                                IMInfo *inf = (IMInfo *)im_list_->data;

                                str_list[i*2 + 1] = inf->id;
                                str_list[i*2 + 2] = inf->cname;
                        }
                        str_list[0] = g_strdup_printf("%u", num_im);
                        final_str = g_strjoinv("\n", str_list);

                        gtk_selection_data_set(sel_data, gdk_atom_intern("UTF8_STRING", FALSE),
                                               8, final_str, strlen(final_str));
                        g_free(str_list[0]);
                        g_free(str_list);
                        g_free(final_str);
                }
		break;

#if 0
                case TARGET_SYMBOL_LIST: {
                        GList *l = model->symbolList;
                        guint num = g_list_length(l);
                        gchar **str_list = NULL;
                        gchar *final_str = NULL;
                        int i;

                        str_list = g_new0(gchar *, num*3 + 2);
                        for (i=0; l; i++, l=g_list_next(l)) {
                                SymDefGroup *pSDG = (SymDefGroup *)l->data;

                                str_list[i*3 + 1] = g_strdup_printf("%u", pSDG->modifier);
                                str_list[i*3 + 2] = g_strdup_printf("%u", pSDG->key);
                                str_list[i*3 + 3] = pSDG->symbol;
                        }
                        str_list[0] = g_strdup_printf("%u", num);
                        final_str = g_strjoinv("\n", str_list);

                        gtk_selection_data_set(sel_data,
                                        gdk_atom_intern("UTF8_STRING", FALSE),
                                        8, final_str, strlen(final_str));
                        i--;
                        for (; i>=0; i--) {
                                g_free(str_list[i*3 + 1]);
                                g_free(str_list[i*3 + 2]);
                        }
                        g_free(str_list[0]);
                        g_free(str_list);
                        g_free(final_str);
                }
                break;

                case TARGET_WORD_LIST: {
                        GList *l = model->wordList;
                        guint num = g_list_length(l);
                        gchar **str_list = NULL;
                        gchar *final_str = NULL;
                        int i;

                        str_list = g_new0(gchar *, num*2 + 2);
                        for (i=0; l; i++, l=g_list_next(l)) {
                                WordDefGroup *pWDG = (WordDefGroup *)l->data;
 
                                str_list[i*2 + 1] = pWDG->key;
                                str_list[i*2 + 2] = pWDG->word;
                        }
                        str_list[0] = g_strdup_printf("%u", num);
                        final_str = g_strjoinv("\n", str_list);

                        gtk_selection_data_set(sel_data,
                                        gdk_atom_intern("UTF8_STRING", FALSE),
                                        8, final_str, strlen(final_str));
                        g_free(str_list[0]);
                        g_free(str_list);
                        g_free(final_str);
                }
                break;
#endif
	}

	g_free(target);
}

/* ------------------------------------------------------------------------- */
static void
set_window_icon(void)
{
	GdkPixbuf *pixbuf = NULL;
	GList *iconlist = NULL;

	pixbuf = gdk_pixbuf_new_from_file(UNIHAN_DATA_DIR "/images/icon.png", NULL);
	if (!pixbuf)
		return;
	iconlist = g_list_append(iconlist, pixbuf);
	gtk_window_set_default_icon_list(iconlist);
	g_list_free(iconlist);
	g_object_unref(G_OBJECT(pixbuf));
}

/* ------------------------------------------------------------------------- */
static gboolean
is_unicode_charset(gchar *charset)
{
	return (charset && 
		(!strcmp("UTF-8", orig_codeset) ||
		 !strcmp("GB18030", orig_codeset)));
}

/* ------------------------------------------------------------------------- */
static gboolean
commit_string_cleared(GtkWidget *w, GdkEventSelection *ev, gpointer data)
{
	if (strcmp("_UNIHAN_COMMIT_STRING", gdk_atom_name(ev->selection)))
		return FALSE;

	DEBUG_LOG("selection cleared; asking for selection");
	gtk_selection_convert(w, ev->selection, gdk_atom_intern("UTF8_STRING", FALSE), ev->time);
	return TRUE;
}

/* ------------------------------------------------------------------------- */
static void
commit_string_received_real(GtkSelectionData *sd, guint time)
{
	int int_list[1];
	char *str_list[1];

	if (strcmp("UTF8_STRING", gdk_atom_name(sd->target))) {
		DEBUG_LOG("selection target != UTF8_STRING");
		return;
	}
	if (!sd->data) {
		DEBUG_LOG("selection has no data?");
		return;
	}
	if (!(sd->data[0])) {
		GtkClipboard *cb = gtk_clipboard_get(GDK_SELECTION_PRIMARY);
#if DEBUG
		int i;
		DEBUG_LOG("selection's first byte is null?");
		DEBUG_LOG("\t\t(length %d) ", sd->length);
		for (i = 0; i < sd->length; ++i) {
			DEBUG_LOG("%02x ", sd->data[i]);
		}
		DEBUG_LOG("\n");
#endif

		// hanwang&wintone workaround: check PRIMARY!
		int_list[0] = UNIHAN_ENGINE_COMMIT;
		str_list[0] = gtk_clipboard_wait_for_text(cb);
		DEBUG_LOG("PRIMARY has: %s", str_list[0]);
		send_to_engine(1, int_list, 1, str_list);
		return;
	}

	// ok, send to engine
	int_list[0] = UNIHAN_ENGINE_COMMIT;
	str_list[0] = sd->data;
	
	DEBUG_LOG("received commit string: %s", str_list[0]);

	send_to_engine(1, int_list, 1, str_list);
}

/* ------------------------------------------------------------------------- */
static void
commit_string_received(GtkWidget *w, GtkSelectionData *seldata, guint time, gpointer data)
{
	DEBUG_LOG("selection converted...");

	if (strcmp("_UNIHAN_COMMIT_STRING", gdk_atom_name(seldata->selection)))
	{
		DEBUG_LOG("selection name != _UNIHAN_COMMIT_STRING");
		return;
	}
	commit_string_received_real(seldata, time);

	gtk_selection_owner_set(window->appletWindow, seldata->selection, time);

	DEBUG_LOG("reclaimed selection owner");
}

/* ------------------------------------------------------------------------- */
static void
applet_window_realize(GtkWidget *w, gpointer data)
{
	XWMHints *wmHints = NULL;
	Atom wmProtocols[2];
	Display *dpy = GDK_DISPLAY();

	// Do our best to convince the window manager _not_ 
	// to give us focus
	wmHints = XGetWMHints(dpy, GDK_WINDOW_XWINDOW(w->window));
        if (wmHints) {
                wmHints->flags |= InputHint;
                wmHints->input = False;
                XSetWMHints(dpy, GDK_WINDOW_XWINDOW(w->window), wmHints);
                XFree(wmHints);
        }

	// Get rid of the WM_TAKE_FOCUS atom that GDK puts onto
	// the window.  See the ICCCM section 4.1.7.
	wmProtocols[0] = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
	wmProtocols[1] = XInternAtom(dpy, "_NET_WM_PING", False);
	XSetWMProtocols(dpy, GDK_WINDOW_XWINDOW(w->window), wmProtocols, 2);
	gdk_window_set_type_hint(w->window, GDK_WINDOW_TYPE_HINT_TOOLBAR);

	gtk_selection_owner_set(w, commit_string_atom, GDK_CURRENT_TIME);

	DEBUG_LOG("claimed selection owner");
}

/* ------------------------------------------------------------------------- */
static void
menu_position_func(GtkMenu *menu, gint *x, gint *y, gboolean *push_in, gpointer data)
{
	GtkWidget *activator = GTK_WIDGET(data);
	gint screenW = gdk_screen_width();
	gint screenH = gdk_screen_height();
	gint menuW, menuH;
	gint menuX, menuY;

	g_return_if_fail(menu != NULL);
	g_return_if_fail(x != NULL);
	g_return_if_fail(y != NULL);

	menuW = GTK_WIDGET(menu)->requisition.width;
	menuH = GTK_WIDGET(menu)->requisition.height;

	if (!gdk_window_get_origin(activator->window, &menuX, &menuY)) {
		return;
	}
	menuX += activator->allocation.x;
	menuY += activator->allocation.y;

	if ((menuY + activator->allocation.height + menuH) <= screenH)
		menuY += activator->allocation.height;
	else if ((menuY - menuH) >= 0)
		menuY -= menuH;
	else if (screenH - (menuY + activator->allocation.height) > menuY)
		menuY += activator->allocation.height;
	else
		menuY -= menuH;

	if ((menuX + menuW) > screenW) {
		menuX = screenW - menuW;
		if (menuX < 0)
			menuX = 0;
	}

	*x = menuX;
	*y = menuY;
}


/* ------------------------------------------------------------------------- */
/**
 * Being called when the punc. virtual keyboard menu item is clicked
 */
static void
punc_kbd_item_handler(GtkCheckMenuItem *item, gpointer data)
{
	int int_values[1];

        DEBUG_LOG("Punc Keyboard menu clicked");

	if (puncKbdIgnoreToggle)
	    return;

	puncKbdIgnoreToggle = TRUE;

	if (item->active) {     // toggle on
		gtk_check_menu_item_set_active(item, TRUE);
	} else {                // toggle off
		gtk_check_menu_item_set_active(item, FALSE);
	}

	int_values[0] = UNIHAN_ENGINE_TOGGLE_PUNC;
	send_to_engine(1, int_values, 0, NULL);

	puncKbdIgnoreToggle = FALSE;
}

static void
us_kbd_item_handler(GtkCheckMenuItem *item, gpointer data)
{
	int int_values[1];

	DEBUG_LOG("US Keyboard menu clicked");

	if (usKbdIgnoreToggle)
	    return;

	usKbdIgnoreToggle = TRUE;

	if (item->active) {     // toggle on
		gtk_check_menu_item_set_active(item, TRUE);
	} else {                // toggle off
		gtk_check_menu_item_set_active(item, FALSE);
	}

	int_values[0] = UNIHAN_ENGINE_TOGGLE_US;
	send_to_engine(1, int_values, 0, NULL);

	usKbdIgnoreToggle = FALSE;
}

#ifdef WITH_HWPENX

/* ------------------------------------------------------------------------- */
static void
hwpenx_start_failed(void)
{
	GtkWidget *d;
	d = gtk_message_dialog_new(GTK_WINDOW(applet),
	    GTK_DIALOG_DESTROY_WITH_PARENT,
	    GTK_MESSAGE_ERROR,
	    GTK_BUTTONS_CLOSE,
	    _("Could not start Hanwang Handwriting!"));
	gtk_dialog_run(GTK_DIALOG (d));
	gtk_widget_destroy(d);

/*
	g_signal_connect_swapped(G_OBJECT(d), "response",
	    G_CALLBACK(gtk_widget_destroy),
	    G_OBJECT(d));
	gtk_widget_show_all(d);
*/

	hwpenxIgnoreToggle = TRUE;
	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(hwpenx_item), FALSE);
	hwpenxIgnoreToggle = FALSE;
}

/* ------------------------------------------------------------------------- */
static void
hwpenx_exited(void)
{
	hwpenxIgnoreToggle = TRUE;
	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(hwpenx_item), FALSE);
	hwpenxIgnoreToggle = FALSE;
}

/* ------------------------------------------------------------------------- */
/**
 * Being called when the handwriting menu item is selected
 */
static void
hwpenx_item_handler(GtkCheckMenuItem *item, gpointer data)
{
	Display* dsp = GDK_WINDOW_XDISPLAY((GTK_WIDGET(item))->window);
	if (hwpenxIgnoreToggle)
	    return;

	hwpenxIgnoreToggle = TRUE;

	if (item->active) {     // toggle on
		if (!is_hwpenx_started()) {
		        char* region;
			region = strndup(locale+3, 2);
			DEBUG_LOG("Starting hwpenx...");
			if ( hwpenx_start(region) ) {
				gtk_check_menu_item_set_active(item, TRUE);
			}
		} else {
			DEBUG_LOG("Unhiding hwpenx...");
			if ( hwpenx_window_show(dsp) ) {
				gtk_check_menu_item_set_active(item, TRUE);
			}
		}
	} else {                // toggle off
		DEBUG_LOG("Hiding hwpenx...");
		if ( hwpenx_window_hide(dsp) ) {
		    	gtk_check_menu_item_set_active(item, FALSE);
		}
	}

	hwpenxIgnoreToggle = FALSE;
}
#endif /* WITH_HWPENX */

#if WTPEN

/* ------------------------------------------------------------------------- */
static void
wtpen_start_failed(void)
{
	GtkWidget *d;
	d = gtk_message_dialog_new(GTK_WINDOW(window->appletWindow),
	    GTK_DIALOG_DESTROY_WITH_PARENT,
	    GTK_MESSAGE_ERROR,
	    GTK_BUTTONS_CLOSE,
	    _("Could not start Wintone Handwriting!"));
	gtk_dialog_run(GTK_DIALOG (d));
	gtk_widget_destroy(d);

/*
	g_signal_connect_swapped(G_OBJECT(d), "response",
	    G_CALLBACK(gtk_widget_destroy),
	    G_OBJECT(d));
	gtk_widget_show_all(d);
*/

	wtpenIgnoreToggle = TRUE;
	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(wtpen_item), FALSE);
	wtpenIgnoreToggle = FALSE;
}

/* ------------------------------------------------------------------------- */
static void
wtpen_exited(void)
{
	wtpenIgnoreToggle = TRUE;
	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(wtpen_item), FALSE);
	wtpenIgnoreToggle = FALSE;
}

/* ------------------------------------------------------------------------- */
/**
 * Being called when the handwriting menu item is selected
 */
static void
wtpen_item_handler(GtkCheckMenuItem *item, gpointer data)
{
	Display* dsp = GDK_WINDOW_XDISPLAY((GTK_WIDGET(item))->window);
	if (wtpenIgnoreToggle)
	    return;

	wtpenIgnoreToggle = TRUE;

	if (item->active) {     // toggle on
		if (!is_wtpen_started()) {
		        char* region;
			region = strndup(locale+3, 2);
			DEBUG_LOG("Starting Wintone Pen Handwriting ...");
			if ( wtpen_start(region) ) {
				gtk_check_menu_item_set_active(item, TRUE);
			}
		} else {
			DEBUG_LOG("Unhiding wtpen...");
			if ( wtpen_window_show(dsp) ) {
				gtk_check_menu_item_set_active(item, TRUE);
			}
		}
	} else {                // toggle off
		DEBUG_LOG("Hiding wtpen...");
		if ( wtpen_window_hide(dsp) ) {
		    	gtk_check_menu_item_set_active(item, FALSE);
		}
	}

	wtpenIgnoreToggle = FALSE;
}
#endif /* WTPEN */

/*---------------------------------------------------------------------------*/
//create a tree of properties;
#if NEW_PROPERTY
#endif
/*--------------------------------------------------------------------------*/
#if NEW_PROPERTY
// this functions can create the tree from properties, and start code here;
PropertyTree * 
status_model_retreive_property_list(UnihanPropertyList*  property_list)
{
	PropertyNode *property_node;
	PropertyTree *property_tree;
	//GNode *root, *child, sibling;
	int i;
	
	property_count = property_list->propertiesNum;
	
	//int root_count = check_key_string_tree(p_property_list);
	DEBUG_LOG("the properties is d%", property_count);
		
	// define the tree struct and malloc the memory 
	property_tree = (PropertyTree*)malloc(sizeof(property_tree));
	memset(property_tree, 0, sizeof(PropertyTree));
			
	property_node = (PropertyNode*)malloc(sizeof(property_node));
	memset(property_node, 0, sizeof(PropertyNode));
	
	for (i = 0; i < property_count && property_list; i++)
	{
		 //int count = strlen(property_list->properties[i].key);
		 char *new_key = property_list->properties[i].key; 
		 char pos = '/';
		 char *address = strrchr(property_list->properties[i].key, pos);
		 int num = 0;
		 if (address)
		   	 num = (int)(address - new_key);
		 char *string = g_strndup(property_list->properties[i].key, num);
		 if (string == NULL)
		 {
			 property_node->property[i].key = property_list->properties[i].key;
             property_node->property[i].label = property_list->properties[i].label;
	         property_node->property[i].icon = property_list->properties[i].icon;
	         property_node->property[i].tip = property_list->properties[i].tip;
	         property_node->property[i].state = property_list->properties[i].state;
			 property_tree->root = g_node_new(property_node);
		 }
		 else
		 {
			 property_node->property[i].key = property_list->properties[i].key;
             property_node->property[i].label = property_list->properties[i].label;
	         property_node->property[i].icon = property_list->properties[i].icon;
	         property_node->property[i].tip = property_list->properties[i].tip;
	         property_node->property[i].state = property_list->properties[i].state;
			 GNode *parent = g_node_find(property_tree->root, G_LEVEL_ORDER, G_TRAVERSE_ALL, string);
	         g_node_append_data(parent, property_node);
		 }
		
	}
	return property_tree;
}
#endif
/*--------------------------------------------------------------------------*/
#if NEW_PROPERTY
#endif
/*--------------------------------------------------------------------------*/
#if NEW_PROPERTY
static gint
check_key_string_tree(char *string)
{
	int n=0;
    char *pos = strchr(string,'/');
    while(pos)
    {
     n++;
     pos=strchr(pos+1,'/');
    }
    return n;
}
#endif
/*---------------------------------------------------------------------------*/
#if NEW_PROPERTY
static gboolean
gnode_traverse_fun(PropertyNode *node, gpointer data)
{
	int n = 0;
	char *pos = strdup(node->property->key);
	while(pos)
	{
		pos = strchr(pos+1, '/');
		return n++;
	}
	if (n == 1 && n == 2)
	{
	    if (node->property->icon)
	    {
		    node->widget = gtk_event_box_new();
		    GtkWidget *image = gtk_image_new_from_file(node->property->icon);
		    gtk_container_add(GTK_CONTAINER(node->widget), image);
		    gtk_box_pack_start(GTK_BOX(window->controls->hbox), node->widget, FALSE, FALSE, 0);
		    gtk_box_reorder_child(GTK_BOX(window->controls->hbox), node->widget, 0);
		    if (node->property->state == UNIHAN_PROPERTY_ACTIVE)
			    gtk_widget_set_sensitive(node->widget, UNIHAN_PROPERTY_ACTIVE);
	    }
	    else
	    {
		    if (node->property->label)
		    {
		        node->widget = gtk_button_new_with_label(node->property->label);
			    gtk_box_pack_start(GTK_BOX(window->controls->hbox), node->widget, FALSE, FALSE, 0);
			    gtk_box_reorder_child(GTK_BOX(window->controls->hbox), node->widget, 0);
			    if (node->property->state == UNIHAN_PROPERTY_ACTIVE)
				    gtk_widget_set_sensitive(node->widget, UNIHAN_PROPERTY_ACTIVE);
		    }
	    }
    }
	
	return FALSE;
}
#endif
/*---------------------------------------------------------------------------*/
#if NEW_PROPERTY
UnihanPropertyList * convert_string_to_properties_list(aux_ext_data_t *aux_ext_data)
{
	int i,num_properties;
	char *string_values, *p;
	char *delim = "|";
	
	UnihanPropertyList *new_property;
	
	num_properties = aux_ext_data->integer_count - 1;
	
	if(!num_properties)
		return NULL;
	
	new_property = (UnihanPropertyList *)malloc(sizeof(UnihanPropertyList));
	memset(new_property, 0, sizeof(UnihanPropertyList));
	
	new_property->propertiesNum = num_properties;
	
	new_property->properties = (UnihanProperty *)malloc(num_properties*sizeof(UnihanProperty));
	
	for(i = 0; i < num_properties; i++)
	{
		string_values = (char *)aux_ext_data->string_list[i+1].ptr;
	
		p = strtok(string_values , delim);
			
		if(strcmp(p,"null")!=0)
		{
			new_property->properties[i].key = strdup(p);
		}else{
			new_property->properties[i].key = NULL;
		}
			
		p = strtok(NULL , delim);
			
		if(strcmp(p,"null")!=0)
		{
			new_property->properties[i].label = strdup(p);
		}else{
			new_property->properties[i].label = NULL;
		}
		
		p = strtok(NULL , delim);
		
		if(strcmp(p,"null")!=0)
		{
			new_property->properties[i].icon = strdup(p);
		}else{
			new_property->properties[i].icon = NULL;
		}
			 
		p = strtok(NULL , delim);
			
		if(strcmp(p,"null")!=0)
		{
			new_property->properties[i].tip = strdup(p);
		}else{
			new_property->properties[i].tip = NULL;
		}
			
		new_property->properties[i].state = aux_ext_data->integer_list[i+1];
	}
	
	
	return new_property;
		
}
#endif
/*---------------------------------------------------------------------------*/
#if NEW_PROPERTY
UnihanProperty * convert_string_to_properties(aux_ext_data_t *aux_ext_data)
{
	int i,num_properties;
	char *string_values, *p;
	char *delim = "|";
	
	UnihanPropertyList *new_property;
	
	num_properties = aux_ext_data->integer_count - 1;
	
	if(!num_properties)
		return NULL;
	
	new_property = (UnihanPropertyList *)malloc(sizeof(UnihanPropertyList));
	memset(new_property, 0, sizeof(UnihanPropertyList));
	
	new_property->propertiesNum = num_properties;
	
	new_property->properties = (UnihanProperty *)malloc(num_properties*sizeof(UnihanProperty));
	
	for(i = 0; i < num_properties; i++)
	{
		string_values = (char *)aux_ext_data->string_list[i+1].ptr;
	
		p = strtok(string_values , delim);
			
		if(strcmp(p,"null")!=0)
		{
			new_property->properties[i].key = strdup(p);
		}else{
			new_property->properties[i].key = NULL;
		}
			
		p = strtok(NULL , delim);
			
		if(strcmp(p,"null")!=0)
		{
			//new_property->properties[i].label = (char*)malloc(sizeof(char)*(strlen(p)+1));
			new_property->properties[i].label = strdup(p);
		}else{
			new_property->properties[i].label = NULL;
		}
		
		p = strtok(NULL , delim);
		
		if(strcmp(p,"null")!=0)
		{
			//new_property->properties[i].icon = (char*)malloc(sizeof(char)*(strlen(p)+1));
			new_property->properties[i].icon = strdup(p);
		}else{
			new_property->properties[i].icon = NULL;
		}
			 
		p = strtok(NULL , delim);
			
		if(strcmp(p,"null")!=0)
		{
			//new_property->properties[i].tip = (char*)malloc(sizeof(char)*(strlen(p)+1));
			new_property->properties[i].tip = strdup(p);
		}else{
			new_property->properties[i].tip = NULL;
		}
			
		new_property->properties[i].state = aux_ext_data->integer_list[i+1];
	}
	
	
	return new_property->properties;
		
}
#endif

void on_Status_In_Tray_toggled(GConfClient *client,
							   guint cnxn_id,
							   GConfEntry *entry,
							   gpointer data)
{
	click_status=0;
	unset_focus_before=0;
	gboolean in_tray = gconf_client_get_bool(client, STATUS_IN_TRAY_KEY, NULL);
	if (in_tray) {
		gint x_coordinate;
		gint y_coordinate;
		gtk_window_get_position(GTK_WINDOW(window->appletWindow), &x_coordinate, &y_coordinate);
		gconf_client_set_int(client, "/apps/sw-unihan/gnome_aux/status/x_coordinate", x_coordinate, NULL);
		gconf_client_set_int(client, "/apps/sw-unihan/gnome_aux/status/y_coordinate", y_coordinate, NULL);
		window->runAsApplet=TRUE;
		gtk_widget_hide_all(window->appletWindow);
		gtk_widget_show_all(window->controls->hbox);
	} else {
		window->runAsApplet=FALSE;
		gtk_widget_hide_all(window->controls->hbox);
		gdk_window_raise(window->appletWindow->window);
		gtk_widget_show_all(window->appletWindow);
		hack_NET_SUPPORTED();
		gint x_coordinate = gconf_client_get_int(client, "/apps/sw-unihan/gnome_aux/status/x_coordinate", NULL);
		gint y_coordinate = gconf_client_get_int(client, "/apps/sw-unihan/gnome_aux/status/y_coordinate", NULL);
		gtk_window_move(GTK_WINDOW(window->appletWindow), x_coordinate, y_coordinate);
	}
	present_applet_window();
	
	if (window->runAsApplet) {
		gtk_widget_hide(window->controls->widthButton);
		gtk_widget_hide(window->controls->puncceButton);
		gtk_widget_hide(window->controls->tcscButton);
		gtk_widget_hide(window->controls->imButton);
		gtk_widget_show(window->controls->icon);
	}else {
		status_model_current_im_set_by_id(model, "English");
		present_applet_window();
	}
}

void on_tc_sc_changed(GConfClient *client,
					  guint cnxn_id,
					  GConfEntry *entry,
					  gpointer data)
{
	int tcsc = gconf_client_get_int(client, TC_SC_KEY, NULL);
	int int_values[2] = { UNIHAN_ENGINE_SET_TCSC_MODE, tcsc };
	send_to_engine(2, int_values, 0, NULL);
}

void on_phrase_mode_changed(GConfClient *client,
					  guint cnxn_id,
					  GConfEntry *entry,
					  gpointer data)
{
	gboolean phrase_mode = gconf_client_get_bool(client, PHRASE_MODE_KEY, NULL);
	int int_values[2] = { UNIHAN_ENGINE_SET_PHRASE_MODE, phrase_mode ? 1 : 0 };
	send_to_engine(2, int_values, 0, NULL);
}

void check_module_info(GConfClient *client,
					  guint cnxn_id,
					  GConfEntry *entry,
					  gpointer data)
{
		int int_values[1];
		int_values[0] = UNIHAN_ENGINE_CHECK_MODULE_INFO;
		send_to_engine(1, int_values, 0, NULL);
}
/*---------------------------------------------------------------------------*/
static void 
link_button_clicked_handler(GtkWidget *widget, gpointer data)
{
	//const gchar *link = gtk_link_button_get_uri(GTK_LINK_BUTTON(widget));
	const gchar *link = "http://www.openrays.org/";
	// FIXME: using Debian's x-www-browser
	// Use a better method when Project Portland/LSB Desktop is ready
	gchar *command = g_strdup_printf("x-www-browser %s", link);
	g_spawn_command_line_async(command, NULL);
	g_free(command);
}

// vi:ts=4:nowrap:cin:expandtab
